• HDU1569 方格取数(2) —— 二分图点带权最大独立集、最小割最大流


    题目链接:https://vjudge.net/problem/HDU-1569

    方格取数(2)

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 6876    Accepted Submission(s): 2198


    Problem Description
    给你一个m*n的格子的棋盘,每个格子里面有一个非负数。
    从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
     
    Input
    包括多个测试实例,每个测试实例包括2整数m,n和m*n个非负数(m<=50,n<=50)
     
    Output
    对于每个测试实例,输出可能取得的最大的和
     
    Sample Input
    3 3 75 15 21 75 15 28 34 70 5
     
    Sample Output
    188
     
    Author
    ailyanlu
     
    Source

    题解:

    1.将n*m的格子建模成二分图。

    2.在二分图的基础上添加源点S和汇点T, 然后从S向所有X集合中的点连一条边, 所有Y集合中的点向T连一条边, 容量均为该点的权值。

    3.X集合的结点与Y集合的结点之间的边的容量为无穷大。在此题中,如果是格子相邻,就需要连边,且是X-->Y。

    4.因此,对于该图中的任意一个割, 将割中的边所对应的结点删掉,就是一个符合条件的解,权值和为所有权和减去割的容量。

    5.根据4可得:只要求出最小割, 就能求出最大权值和独立集。

    代码如下:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <vector>
      6 #include <cmath>
      7 #include <queue>
      8 #include <stack>
      9 #include <map>
     10 #include <string>
     11 #include <set>
     12 using namespace std;
     13 typedef long long LL;
     14 const int INF = 2e9;
     15 const LL LNF = 9e18;
     16 const int mod = 1e9+7;
     17 const int MAXM = 1e5+10;
     18 const int MAXN = 2500+10;
     19 
     20 struct Edge
     21 {
     22     int to, next, cap, flow;
     23 }edge[MAXM];
     24 int tot, head[MAXN];
     25 int gap[MAXN], dep[MAXN], pre[MAXN], cur[MAXN];
     26 
     27 void init()
     28 {
     29     tot = 0;
     30     memset(head, -1, sizeof(head));
     31 }
     32 
     33 void add(int u, int v, int w)
     34 {
     35     edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0;
     36     edge[tot].next = head[u]; head[u] = tot++;
     37     edge[tot].to = u; edge[tot].cap = 0; edge[tot].flow = 0;
     38     edge[tot].next = head[v]; head[v] = tot++;
     39 }
     40 
     41 int sap(int start, int end, int nodenum)
     42 {
     43     memset(dep, 0, sizeof(dep));
     44     memset(gap, 0, sizeof(gap));
     45     memcpy(cur, head, sizeof(head));
     46     int u = pre[start] = start, maxflow = 0,aug = INF;
     47     gap[0] = nodenum;
     48     while(dep[start]<nodenum)
     49     {
     50         loop:
     51         for(int i = cur[u]; i!=-1; i = edge[i].next)
     52         {
     53             int v = edge[i].to;
     54             if(edge[i].cap-edge[i].flow && dep[u]==dep[v]+1)
     55             {
     56                 aug = min(aug, edge[i].cap-edge[i].flow);
     57                 pre[v] = u;
     58                 cur[u] = i;
     59                 u = v;
     60                 if(v==end)
     61                 {
     62                     maxflow += aug;
     63                     for(u = pre[u]; v!=start; v = u,u = pre[u])
     64                     {
     65                         edge[cur[u]].flow += aug;
     66                         edge[cur[u]^1].flow -= aug;
     67                     }
     68                     aug = INF;
     69                 }
     70                 goto loop;
     71             }
     72         }
     73         int mindis = nodenum;
     74         for(int i = head[u]; i!=-1; i = edge[i].next)
     75         {
     76             int v=edge[i].to;
     77             if(edge[i].cap-edge[i].flow && mindis>dep[v])
     78             {
     79                 cur[u] = i;
     80                 mindis = dep[v];
     81             }
     82         }
     83         if((--gap[dep[u]])==0)break;
     84         gap[dep[u]=mindis+1]++;
     85         u = pre[u];
     86     }
     87     return maxflow;
     88 }
     89 
     90 int n, m, g[55][55];
     91 int main()
     92 {
     93     while(scanf("%d%d", &n, &m)!=EOF)
     94     {
     95         int sum = 0;
     96         for(int i = 0; i<n; i++)
     97         for(int j = 0; j<m; j++)
     98             scanf("%d", &g[i][j]), sum += g[i][j];
     99 
    100         int start = n*m, end = n*m+1;
    101         init();
    102         for(int i = 0; i<n; i++)
    103         for(int j = 0; j<m; j++)
    104         {
    105             if((i+j)%2)
    106             {
    107                 add(start, i*m+j, g[i][j]);
    108                 if(i!=0)  add(i*m+j, (i-1)*m+j, INF);
    109                 if(i!=n-1) add(i*m+j, (i+1)*m+j, INF);
    110                 if(j!=0) add(i*m+j, i*m+j-1, INF);
    111                 if(j!=m-1) add(i*m+j, i*m+j+1, INF);
    112             }
    113             else
    114                 add(i*m+j, end, g[i][j]);
    115         }
    116 
    117         sum -= sap(start, end, n*m+2);
    118         printf("%d
    ", sum);
    119     }
    120 }
    View Code
  • 相关阅读:
    一些收藏
    Gradle Groovy Application 打包可执行jar
    定时跑批过程中,为啥jenkins会偶现卡住?
    什么才算自动化测试?
    使用wireshark解密tls和使用firefox浏览器禁用DiffieHellman密钥交换算法
    BurpSuite Intruder模块的GrepMatch功能
    RDP报错“出现身份验证错误,无法连接到本地安全机构”的解决方法
    PDF_XSS漏洞
    一次sqlmap扫出的Oracle数据库时间盲注的手工复现验证
    C语言程序设计
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8124507.html
Copyright © 2020-2023  润新知