zoukankan      html  css  js  c++  java
  • HDU 1569 方格取数(2)(最大流最小割の最大权独立集)

    Description

    给你一个m*n的格子的棋盘,每个格子里面有一个非负数。 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
     

    Input

    包括多个测试实例,每个测试实例包括2整数m,n和m*n个非负数(m<=50,n<=50)
     

    Output

    对于每个测试实例,输出可能取得的最大的和

    题目大意:这么短还中文就没大意了,唯一要注意的就是输入的第一个是行第二个是列……

    思路:这题为最大权独立集(所选的点之间都没有边)。建立一个最大流的二分图,i+j为偶数的放左边,源点S连一条边到它,容量为格子里的数,其余放右边,连一条边到汇点T,容量还是格子里的数,相邻的都从左到右连一条边,容量为无穷大。所有数字之和减去最大流即为答案。

    小证明:这样构图求出的最大流为最小权覆盖集(所有边至少被一个点覆盖),详见POJ 3308 Paratroopers(最大流最小割の最小点权覆盖)

    而最小权覆盖集与最大权独立集是对偶图,把最小权覆盖集里的点都取反,就可以得到一个最大权独立集,所以总权 = 最小权覆盖集 + 最大权独立集。详见二分图中的对偶问题

    代码(15MS):

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <queue>
      5 using namespace std;
      6 
      7 const int MAXN = 3000;
      8 const int MAXE = 30010;
      9 const int INF = 0x3fff3fff;
     10 
     11 struct SAP {
     12     int head[MAXN], dis[MAXN], pre[MAXN], cur[MAXN], gap[MAXN];
     13     int to[MAXE], next[MAXE], flow[MAXE];
     14     int n, st, ed, ecnt;
     15 
     16     void init() {
     17         memset(head, 0, sizeof(head));
     18         ecnt = 2;
     19     }
     20 
     21     void add_edge(int u, int v, int c) {
     22         to[ecnt] = v; flow[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++;
     23         to[ecnt] = u; flow[ecnt] = 0; next[ecnt] = head[v]; head[v] = ecnt++;
     24         //printf("%d->%d flow = %d
    ", u, v, c);
     25     }
     26 
     27     void bfs() {
     28         memset(dis, 0x3f, sizeof(dis));
     29         queue<int> que; que.push(ed);
     30         dis[ed] = 0;
     31         while(!que.empty()) {
     32             int u = que.front(); que.pop();
     33             ++gap[dis[u]];
     34             for(int p = head[u]; p; p = next[p]) {
     35                 int &v = to[p];
     36                 if(flow[p ^ 1] && dis[v] > n) {
     37                     dis[v] = dis[u] + 1;
     38                     que.push(v);
     39                 }
     40             }
     41         }
     42     }
     43 
     44     int Max_flow(int ss, int tt, int nn) {
     45         st = ss; ed = tt; n = nn;
     46         int ans = 0, minFlow = INF, u;
     47         for(int i = 0; i <= n; ++i) {
     48             cur[i] = head[i];
     49             gap[i] = 0;
     50         }
     51         u = pre[st] = st;
     52         bfs();
     53         while(dis[st] < n) {
     54             bool flag = false;
     55             for(int &p = cur[u]; p; p = next[p]) {
     56                 int &v = to[p];
     57                 if(flow[p] && dis[u] == dis[v] + 1) {
     58                     flag = true;
     59                     minFlow = min(minFlow, flow[p]);
     60                     pre[v] = u;
     61                     u = v;
     62                     if(u == ed) {
     63                         ans += minFlow;
     64                         while(u != st) {
     65                             u = pre[u];
     66                             flow[cur[u]] -= minFlow;
     67                             flow[cur[u] ^ 1] += minFlow;
     68                         }
     69                         minFlow = INF;
     70                     }
     71                     break;
     72                 }
     73             }
     74             if(flag) continue;
     75             int minDis = n - 1;
     76             for(int p = head[u]; p; p = next[p]) {
     77                 int &v = to[p];
     78                 if(flow[p] && minDis > dis[v]) {
     79                     minDis = dis[v];
     80                     cur[u] = p;
     81                 }
     82             }
     83             if(--gap[dis[u]] == 0) break;
     84             gap[dis[u] = minDis + 1]++;
     85             u = pre[u];
     86         }
     87         return ans;
     88     }
     89 } G;
     90 
     91 int n, m;
     92 int mat[55][55];
     93 
     94 int main() {
     95     while(scanf("%d%d", &n, &m) != EOF) {
     96         for(int i = 1; i <= n; ++i)
     97             for(int j = 1; j <= m; ++j) scanf("%d", &mat[i][j]);
     98         G.init();
     99         int ss = n * m + 1, tt = n * m + 2;
    100         int cnt = 0, sum = 0;
    101         for(int i = 1; i <= n; ++i) {
    102             for(int j = 1; j <= m; ++j) {
    103                 ++cnt; sum += mat[i][j];
    104                 if((i + j) & 1) {
    105                     G.add_edge(ss, cnt, mat[i][j]);
    106                     if(j != 1) G.add_edge(cnt, cnt - 1, INF);
    107                     if(i != 1) G.add_edge(cnt, cnt - m, INF);
    108                     if(j != m) G.add_edge(cnt, cnt + 1, INF);
    109                     if(i != n) G.add_edge(cnt, cnt + m, INF);
    110                 }
    111                 else G.add_edge(cnt, tt, mat[i][j]);
    112             }
    113         }
    114         printf("%d
    ", sum - G.Max_flow(ss, tt, tt));
    115     }
    116 }
    View Code
  • 相关阅读:
    真正的成长就是颠覆你以前的世界观
    别蠢到用暴露自己软肋的方式,去表达你对别人的信任
    微信企业号的JAVA开发平台
    谁的青春不迷茫
    我才懒得去想我十年后是什么样子,我只在乎十年后的自己怎么看现在的我。
    2016年03月书单
    在人山人海里,你不必记得我
    Android模拟器Intel Atom下载安装配置
    Git与TortoiseGit使用方法
    Android开发环境搭建
  • 原文地址:https://www.cnblogs.com/oyking/p/3250371.html
Copyright © 2011-2022 走看看