51nod 算法马拉松4 D装盒子(网络流 / 二分图最优匹配)
2015-08-04 11:35
495 查看
装盒子
基准时间限制:1 秒 空间限制:131072 KB 分值: 160
有n个长方形盒子,第i个长度为Li,宽度为Wi,我们需要把他们套放。注意一个盒子只可以套入长和宽分别不小于它的盒子,并且一个盒子里最多只能直接装入另外一个盒子 (但是可以不断嵌套),例如1 * 1 可以套入2 * 1,而2 * 1再套入2 * 2。套入之后盒子占地面积是最外面盒子的占地面积。给定N个盒子大小,求最终最小的总占地面积。
Input
Output
Input示例
Output示例
基准时间限制:1 秒 空间限制:131072 KB 分值: 160
有n个长方形盒子,第i个长度为Li,宽度为Wi,我们需要把他们套放。注意一个盒子只可以套入长和宽分别不小于它的盒子,并且一个盒子里最多只能直接装入另外一个盒子 (但是可以不断嵌套),例如1 * 1 可以套入2 * 1,而2 * 1再套入2 * 2。套入之后盒子占地面积是最外面盒子的占地面积。给定N个盒子大小,求最终最小的总占地面积。
Input
第一行一个数N表示盒子的个数。 接下来N行,每行两个正整数,表示每个盒子的长度和宽度。 所有整数都是正的(N,以及盒子的长宽),且不超过200。
Output
一行一个整数表示最终最小的占地面积。
Input示例
3 1 1 1 2 2 1
Output示例
4 想了很久,发现具有二分图的性质:每个点只能被包含在另外一个点当中。那么拆点,然后A可以被包含在B中就由左侧的A向右侧的B建一条边,这时构成一个二分图. 由于题目要求是的占地面积最小,那么考虑最大匹配时的连边情况,若最大匹配有A->B的这一条边存在,也就说明A被放在了B中,那么占地面积是不要包括A的面积的,所以考虑连边时,将A->B的边权值设为A的面积,那么最后答案就是所有点面积的总和 减去 最优匹配的权值和。 这里n<=200,所以考虑要使用N^3的最优匹配. 同样可以用二分图的题一定可以用网络流,然后网络流跑了一发(最小费用最大流)。 最后二分图最优匹配32ms,而网络流64ms
#pragma comment(linker, "/STACK:1677721600") #include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <ctime> #include <bitset> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f #define inf (-((LL)1<<40)) #define lson k<<1, L, (L + R)>>1 #define rson k<<1|1, ((L + R)>>1) + 1, R #define mem0(a) memset(a,0,sizeof(a)) #define mem1(a) memset(a,-1,sizeof(a)) #define mem(a, b) memset(a, b, sizeof(a)) #define FIN freopen("in.txt", "r", stdin) #define FOUT freopen("out.txt", "w", stdout) #define rep(i, a, b) for(int i = a; i <= b; i ++) #define dec(i, a, b) for(int i = a; i >= b; i --) //typedef __int64 LL; typedef long long LL; typedef pair<int, int> Pair; const int MAXN = 200 + 10; const int MAXM = 110000; const double eps = 1e-12; LL MOD = 1000000007; int n; struct KM { const static int maxn = 1e3 + 7; int A[maxn], B[maxn]; int visA[maxn], visB[maxn]; int match[maxn], slack[maxn], Map[maxn][maxn]; int M, H; void add(int u, int v, int w) { Map[u][v] = w; } bool find_path ( int i ) { visA[i] = true; for ( int j = 0; j < H; j++ ) { if ( !visB[j] && A[i] + B[j] == Map[i][j] ) { visB[j] = true; if (match[j] == -1 || find_path(match[j])) { match[j] = i; return true; } } else if ( A[i] + B[j] > Map[i][j] ) //j属于B,且不在交错路径中 slack[j] = min(slack[j], A[i] + B[j] - Map[i][j]); } return false; } int solve (int M, int H) { this->M = M; this->H = H; int i, j, d; memset(A, 0, sizeof(A)); memset(B, 0, sizeof(B)); memset(match, -1, sizeof(match)); for ( i = 0; i < M; i++ ) for ( j = 0; j < H; j++ ) A[i] = max (Map[i][j], A[i]); for ( i = 0; i < M; i++ ) { for ( j = 0; j < H; j++ ) slack[j] = INF; while ( 1 ) { memset(visA, 0, sizeof(visA)); memset(visB, 0, sizeof(visB)); if ( find_path ( i ) ) break; //从i点出发找到交错路径则跳出循环 for ( d = INF, j = 0; j < H; j++ ) //取最小的slack[j] if (!visB[j] && d > slack[j]) d = slack[j]; for ( j = 0; j < M; j++ ) //集合A中位于交错路径上的-d if ( visA[j] ) A[j] -= d; for ( j = 0; j < H; j++ ) //集合B中位于交错路径上的+d if ( visB[j] ) B[j] += d; else slack[j] -= d; //注意修改不在交错路径上的slack[j] } } int res = 0; for ( j = 0; j < H; j++ ) res += Map[match[j]][j]; return res; } }km;//点从0开始编号 struct Node { int w, h; bool operator < (const Node &A) const { if(w != A.w) return w < A.w; return h < A.h; } bool operator == (const Node &A) const { return w == A.w && h == A.h; } }r[MAXN]; void handle() { sort(r + 1, r + n + 1); int cnt = 1; rep (i, 2, n) if(!(r[i] == r[i - 1])) { r[++cnt] = r[i]; } n = cnt; } int solve() { int ans = 0; rep (i, 1, n) { scanf("%d %d", &r[i].w, &r[i].h); } handle(); rep (i, 1, n) ans += r[i].w * r[i].h; rep (i, 1, n) rep (j, 1, n) if(i != j && r[i].h >= r[j].h && r[i].w >= r[j].w) { km.add(j - 1, i - 1, r[j].w * r[j].h); } ans -= km.solve(n, n); cout << ans << endl; } int main() { // FIN; cin >> n; solve(); return 0; }
#pragma comment(linker, "/STACK:1677721600") #include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <ctime> #include <bitset> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f #define inf (-((LL)1<<40)) #define lson k<<1, L, (L + R)>>1 #define rson k<<1|1, ((L + R)>>1) + 1, R #define mem0(a) memset(a,0,sizeof(a)) #define mem1(a) memset(a,-1,sizeof(a)) #define mem(a, b) memset(a, b, sizeof(a)) #define FIN freopen("in.txt", "r", stdin) #define FOUT freopen("out.txt", "w", stdout) #define rep(i, a, b) for(int i = a; i <= b; i ++) #define dec(i, a, b) for(int i = a; i >= b; i --) //typedef __int64 LL; typedef long long LL; typedef pair<int, int> Pair; const int MAXN = 800 + 10; const int MAXM = 110000; const double eps = 1e-12; LL MOD = 1000000007; //以下是使用邻接表存边,不是使用vector,某些时候比上述要稍快一下 /*******************************************************************/ struct Edge { int to, cap, flow, cost, next; Edge(){} Edge(int _n, int _v, int _c, int _f, int _cost){ next = _n; to = _v; cap = _c; flow = _f; cost = _cost; } }; struct MCMF { int n, m, src, des; int head[MAXN], tot; Edge edges[MAXM]; int inq[MAXN]; int d[MAXN]; int p[MAXN]; int a[MAXN]; void init(int n, int src, int des) { this->tot = 0; this->n = n; this->src = src; this->des = des; mem1(head); } void add_edge(int from, int to, int cap, int cost) { edges[tot] = Edge(head[from], to, cap, 0, cost); head[from] = tot ++; edges[tot] = Edge(head[to], from, 0, 0, -cost); head[to] = tot ++; } bool bellman_ford(int s, int t, int& flow, int& cost) { for(int i = 0; i < n; i ++) { d[i] = INF; inq[i] = 0; } d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF; queue<int>Q; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = false; for(int i = head[u]; i != -1; i = edges[i].next) { int v = edges[i].to; if(edges[i].cap > edges[i].flow && d[v] > d[u] + edges[i].cost) { d[v] = d[u] + edges[i].cost; p[v] = i; a[v] = min(a[u], edges[i].cap - edges[i].flow); if(!inq[v]) { Q.push(v); inq[v] = 1; } } } } if(d[t] >= 0) return false; flow += a[t]; cost += d[t] * a[t]; int u = t; while(u != s) { edges[p[u]].flow += a[t]; edges[p[u]^1].flow -= a[t]; u = edges[p[u]^1].to; } return true; } int min_cost() { int flow = 0, cost = 0; while(bellman_ford(src, des, flow, cost)); return cost; } }mcmf; /***************************************************************/ struct Node { int w, h; bool operator < (const Node &A) const { if(w != A.w) return w < A.w; return h < A.h; } bool operator == (const Node &A) const { return w == A.w && h == A.h; } }r[MAXN]; int n; void handle() { sort(r + 1, r + n + 1); int cnt = 1; rep (i, 2, n) if(!(r[i] == r[i - 1])) { r[++cnt] = r[i]; } n = cnt; } int solve() { int ans = 0; rep (i, 1, n) { scanf("%d %d", &r[i].w, &r[i].h); } handle(); mcmf.init(2 * (n + 1), 0, 2 * n + 1); rep (i, 1, n) { ans += r[i].w * r[i].h; mcmf.add_edge(mcmf.src, 2 * i - 1, 1, 0); mcmf.add_edge(2 * i, mcmf.des, 1, 0); } rep (i, 1, n) rep (j, 1, n) if(i != j && r[i].h >= r[j].h && r[i].w >= r[j].w) { mcmf.add_edge(2 * j - 1, 2 * i, 1, -r[j].w * r[j].h); } ans += mcmf.min_cost(); cout << ans << endl; } int main() { // FIN; cin >> n; solve(); return 0; }
相关文章推荐
- TCP/IP三次握手详解
- the import javax.serlet cannot be solved.和Httpservlet cannot be resolved to a type
- CentOS6.6 Install Apache httpd and PHP and MySQL
- web.config中的httpModules与httpHandlers[转载]
- HTTP协议详解
- http请求的基本过程
- 机器学习03(贝叶斯网络)
- 此集合已经采用方案 http 的地址。此集合中每个方案中最多只能包含一个地址。
- Http请求与响应格式
- Https协议相关
- 7月第4周网络安全报告:被篡改的.COM网站占75.4%
- Https(SSL/TLS)原理详解
- android利用广播全局监听网络。
- 计算机网络面试题
- 南邮 OJ 1075 社会关系网络
- The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path 错误
- 计算机网络面试题
- BP单隐层神经网络 代码实现 以及 详细步骤
- 帧同步在竞技类网络游戏中的应用
- C,C++经典笔试题(答案)转自:http://blog.163.com/jianhuali0118@126/blog/static/377499702008230104125229/