zoukankan      html  css  js  c++  java
  • 51nod 算法马拉松4 D装盒子(网络流 / 二分图最优匹配)

     
    基准时间限制: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

      1 #pragma comment(linker, "/STACK:1677721600")
      2 #include <map>
      3 #include <set>
      4 #include <stack>
      5 #include <queue>
      6 #include <cmath>
      7 #include <ctime>
      8 #include <bitset>
      9 #include <vector>
     10 #include <cstdio>
     11 #include <cctype>
     12 #include <cstring>
     13 #include <cstdlib>
     14 #include <iostream>
     15 #include <algorithm>
     16 using namespace std;
     17 #define INF 0x3f3f3f3f
     18 #define inf (-((LL)1<<40))
     19 #define lson k<<1, L, (L + R)>>1
     20 #define rson k<<1|1,  ((L + R)>>1) + 1, R
     21 #define mem0(a) memset(a,0,sizeof(a))
     22 #define mem1(a) memset(a,-1,sizeof(a))
     23 #define mem(a, b) memset(a, b, sizeof(a))
     24 #define FIN freopen("in.txt", "r", stdin)
     25 #define FOUT freopen("out.txt", "w", stdout)
     26 #define rep(i, a, b) for(int i = a; i <= b; i ++)
     27 #define dec(i, a, b) for(int i = a; i >= b; i --)
     28 
     29 //typedef __int64 LL;
     30 typedef long long LL;
     31 typedef pair<int, int> Pair;
     32 const int MAXN = 200 + 10;
     33 const int MAXM = 110000;
     34 const double eps = 1e-12;
     35 LL MOD = 1000000007;
     36 
     37 int n;
     38 
     39 struct KM {
     40     const static int maxn = 1e3 + 7;
     41     int A[maxn], B[maxn];
     42     int visA[maxn], visB[maxn];
     43     int match[maxn], slack[maxn], Map[maxn][maxn];
     44     int M, H;
     45 
     46     void add(int u, int v, int w) {
     47         Map[u][v] = w;
     48     }
     49     bool find_path ( int i ) {
     50         visA[i] = true;
     51         for ( int j = 0; j < H; j++ ) {
     52             if ( !visB[j] && A[i] + B[j] == Map[i][j] ) {
     53                 visB[j] = true;
     54                 if (match[j] == -1 || find_path(match[j])) {
     55                     match[j] = i;
     56                     return true;
     57                 }
     58             } else if ( A[i] + B[j] > Map[i][j] ) //j属于B,且不在交错路径中
     59                 slack[j] = min(slack[j], A[i] + B[j] - Map[i][j]);
     60         }
     61         return false;
     62     }
     63 
     64     int solve (int M, int H) {
     65         this->M = M; this->H = H;
     66         int i, j, d;
     67         memset(A, 0, sizeof(A));
     68         memset(B, 0, sizeof(B));
     69         memset(match, -1, sizeof(match));
     70         for ( i = 0; i < M; i++ )
     71             for ( j = 0; j < H; j++ )
     72                 A[i] = max (Map[i][j], A[i]);
     73         for ( i = 0; i < M; i++ ) {
     74             for ( j = 0; j < H; j++ )
     75                 slack[j] = INF;
     76             while ( 1 ) {
     77                 memset(visA, 0, sizeof(visA));
     78                 memset(visB, 0, sizeof(visB));
     79                 if ( find_path ( i ) ) break; //从i点出发找到交错路径则跳出循环
     80                 for ( d = INF, j = 0; j < H; j++ ) //取最小的slack[j]
     81                     if (!visB[j] && d > slack[j]) d = slack[j];
     82                 for ( j = 0; j < M; j++ ) //集合A中位于交错路径上的-d
     83                     if ( visA[j] ) A[j] -= d;
     84                 for ( j = 0; j < H; j++ ) //集合B中位于交错路径上的+d
     85                     if ( visB[j] ) B[j] += d;
     86                     else slack[j] -= d; //注意修改不在交错路径上的slack[j]
     87             }
     88         }
     89         int res = 0;
     90         for ( j = 0; j < H; j++ )
     91             res += Map[match[j]][j];
     92         return res;
     93     }
     94 }km;//点从0开始编号
     95 
     96 struct Node {
     97     int w, h;
     98     bool operator < (const Node &A) const {
     99         if(w != A.w) return w < A.w;
    100         return h < A.h;
    101     }
    102     bool operator == (const Node &A) const {
    103         return w == A.w && h == A.h;
    104     }
    105 }r[MAXN];
    106 
    107 void handle() {
    108     sort(r + 1, r + n + 1);
    109     int cnt = 1;
    110     rep (i, 2, n) if(!(r[i] == r[i - 1])) {
    111         r[++cnt] = r[i];
    112     }
    113     n = cnt;
    114 }
    115 
    116 int solve() {
    117     int ans = 0;
    118     rep (i, 1, n) {
    119         scanf("%d %d", &r[i].w, &r[i].h);
    120     }
    121     handle();
    122     rep (i, 1, n) ans += r[i].w * r[i].h;
    123     rep (i, 1, n) rep (j, 1, n) if(i != j && r[i].h >= r[j].h && r[i].w >= r[j].w) {
    124         km.add(j - 1, i - 1, r[j].w * r[j].h);
    125     }
    126     ans -= km.solve(n, n);
    127     cout << ans << endl;
    128 }
    129 
    130 int main()
    131 {
    132 //    FIN;
    133     cin >> n;
    134     solve();
    135     return 0;
    136 }
      1 #pragma comment(linker, "/STACK:1677721600")
      2 #include <map>
      3 #include <set>
      4 #include <stack>
      5 #include <queue>
      6 #include <cmath>
      7 #include <ctime>
      8 #include <bitset>
      9 #include <vector>
     10 #include <cstdio>
     11 #include <cctype>
     12 #include <cstring>
     13 #include <cstdlib>
     14 #include <iostream>
     15 #include <algorithm>
     16 using namespace std;
     17 #define INF 0x3f3f3f3f
     18 #define inf (-((LL)1<<40))
     19 #define lson k<<1, L, (L + R)>>1
     20 #define rson k<<1|1,  ((L + R)>>1) + 1, R
     21 #define mem0(a) memset(a,0,sizeof(a))
     22 #define mem1(a) memset(a,-1,sizeof(a))
     23 #define mem(a, b) memset(a, b, sizeof(a))
     24 #define FIN freopen("in.txt", "r", stdin)
     25 #define FOUT freopen("out.txt", "w", stdout)
     26 #define rep(i, a, b) for(int i = a; i <= b; i ++)
     27 #define dec(i, a, b) for(int i = a; i >= b; i --)
     28 
     29 //typedef __int64 LL;
     30 typedef long long LL;
     31 typedef pair<int, int> Pair;
     32 const int MAXN = 800 + 10;
     33 const int MAXM = 110000;
     34 const double eps = 1e-12;
     35 LL MOD = 1000000007;
     36 
     37 //以下是使用邻接表存边,不是使用vector,某些时候比上述要稍快一下
     38 /*******************************************************************/
     39 struct Edge {
     40     int to, cap, flow, cost, next;
     41     Edge(){}
     42     Edge(int _n, int _v, int _c, int _f, int _cost){
     43         next = _n; to = _v; cap = _c;
     44         flow = _f; cost = _cost;
     45     }
     46 };
     47 
     48 struct MCMF
     49 {
     50     int n, m, src, des;
     51     int head[MAXN], tot;
     52     Edge edges[MAXM];
     53     int inq[MAXN];
     54     int d[MAXN];
     55     int p[MAXN];
     56     int a[MAXN];
     57 
     58     void init(int n, int src, int des) {
     59         this->tot = 0;
     60         this->n = n;
     61         this->src = src;
     62         this->des = des;
     63         mem1(head);
     64     }
     65 
     66     void add_edge(int from, int to, int cap, int cost) {
     67         edges[tot] = Edge(head[from], to, cap, 0, cost);
     68         head[from] = tot ++;
     69         edges[tot] = Edge(head[to], from, 0, 0, -cost);
     70         head[to] = tot ++;
     71     }
     72 
     73     bool bellman_ford(int s, int t, int& flow, int& cost) {
     74         for(int i = 0; i < n; i ++) {
     75             d[i] = INF;
     76             inq[i] = 0;
     77         }
     78         d[s] = 0; inq[s] = 1;
     79         p[s] = 0; a[s] = INF;
     80 
     81         queue<int>Q;
     82         Q.push(s);
     83         while(!Q.empty()) {
     84             int u = Q.front(); Q.pop();
     85             inq[u] = false;
     86             for(int i = head[u]; i != -1; i = edges[i].next) {
     87                 int v = edges[i].to;
     88                 if(edges[i].cap > edges[i].flow && d[v] > d[u] + edges[i].cost) {
     89                     d[v] = d[u] + edges[i].cost;
     90                     p[v] = i;
     91                     a[v] = min(a[u], edges[i].cap - edges[i].flow);
     92                     if(!inq[v]) {
     93                         Q.push(v);
     94                         inq[v] = 1;
     95                     }
     96                 }
     97             }
     98         }
     99         if(d[t] >= 0) return false;
    100 
    101         flow += a[t];
    102         cost += d[t] * a[t];
    103 
    104         int u = t;
    105         while(u != s) {
    106             edges[p[u]].flow += a[t];
    107             edges[p[u]^1].flow -= a[t];
    108             u = edges[p[u]^1].to;
    109         }
    110         return true;
    111     }
    112 
    113     int min_cost() {
    114         int flow = 0, cost = 0;
    115         while(bellman_ford(src, des, flow, cost));
    116         return cost;
    117     }
    118 
    119 }mcmf;
    120 /***************************************************************/
    121 
    122 
    123 struct Node {
    124     int w, h;
    125     bool operator < (const Node &A) const {
    126         if(w != A.w) return w < A.w;
    127         return h < A.h;
    128     }
    129     bool operator == (const Node &A) const {
    130         return w == A.w && h == A.h;
    131     }
    132 }r[MAXN];
    133 int n;
    134 
    135 
    136 void handle() {
    137     sort(r + 1, r + n + 1);
    138     int cnt = 1;
    139     rep (i, 2, n) if(!(r[i] == r[i - 1])) {
    140         r[++cnt] = r[i];
    141     }
    142     n = cnt;
    143 }
    144 
    145 int solve() {
    146     int ans = 0;
    147     rep (i, 1, n) {
    148         scanf("%d %d", &r[i].w, &r[i].h);
    149     }
    150     handle();
    151     mcmf.init(2 * (n + 1), 0, 2 * n + 1);
    152     rep (i, 1, n) {
    153         ans += r[i].w * r[i].h;
    154         mcmf.add_edge(mcmf.src, 2 * i - 1, 1, 0);
    155         mcmf.add_edge(2 * i, mcmf.des, 1, 0);
    156     }
    157     rep (i, 1, n) rep (j, 1, n) if(i != j && r[i].h >= r[j].h && r[i].w >= r[j].w) {
    158         mcmf.add_edge(2 * j - 1, 2 * i, 1, -r[j].w * r[j].h);
    159     }
    160     ans += mcmf.min_cost();
    161     cout << ans << endl;
    162 }
    163 
    164 int main()
    165 {
    166 //    FIN;
    167     cin >> n;
    168     solve();
    169     return 0;
    170 }
  • 相关阅读:
    玩游戏(dfs)
    Find them, Catch them(并查集)
    Shredding Company(dfs)
    Sudoku(dfs)
    Network Saboteur(dfs)
    棋盘问题(dfs)
    Curling 2.0(dfs)
    A Knight's Journey(dfs)
    15. 3Sum
    12. Integer to Roman
  • 原文地址:https://www.cnblogs.com/gj-Acit/p/4701563.html
Copyright © 2011-2022 走看看