OIIIIIIII

「网络流24题」「LuoguP2774」方格取数问题(最大流 最小割

Description


在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。对于给定的方格棋盘,按照取数要求编程找出总和最大的数。

Input


第 1 行有 2 个正整数 m 和 n,分别表示棋盘的行数和列数。接下来的 m 行,每行有 n 个正整数,表示棋盘方格中的数。

Output


程序运行结束时,将取数的最大总和输出

Sample Input


3 3
1 2 3
3 2 3
2 3 1

Sample Output


11

Hint


m,n<=100

题解


因为相邻两个数不能同时取的题设要求,像国际象棋棋盘一样染色 得到二分图

然后S向每个黑点连边,容量为点权

每个白点向T连边,容量为点权

最后每个黑点到能到的白点(上下左右)连边,容量为INF(表示这些边中需要割掉一些)

最后跑一遍最大流 利用最大流最小割定理可得此为最小割(最少要割掉的点权) ans=总点权-最小割

 1 #include<queue>
 2 #include<cmath>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<iostream>
 6 using namespace std;
 7 const int INF=99999999;
 8 struct emm{
 9     int e,f,v;
10 }a[1000007];
11 int h[10007];
12 int tot=1;
13 void con(int x,int y,int l)
14 {
15     if(y==-1)return;
16     a[++tot].f=h[x];
17     h[x]=tot;
18     a[tot].e=y;
19     a[tot].v=l;
20     a[++tot].f=h[y];
21     h[y]=tot;
22     a[tot].e=x;
23     return;
24 }
25 int tu[107][107];
26 int num[107][107];
27 queue<int>q;
28 int d[10007];
29 int m,n,s,t;
30 bool bfs()
31 {
32     memset(d,0,sizeof(d));
33     d[s]=1;
34     q.push(s);
35     while(!q.empty())
36     {
37         int x=q.front();q.pop();
38         for(int i=h[x];i;i=a[i].f)
39         if(!d[a[i].e]&&a[i].v)
40         {
41             d[a[i].e]=d[x]+1;
42             q.push(a[i].e);
43         }
44     }
45     return d[t];
46 }
47 int dfs(int x,int al)
48 {
49     if(x==t||!al)return al;
50     int fl=0;
51     for(int i=h[x];i;i=a[i].f)
52     if(d[a[i].e]==d[x]+1&&a[i].v)
53     {
54         int f=dfs(a[i].e,min(a[i].v,al));
55         if(f)
56         {
57             fl+=f;
58             al-=f;
59             a[i].v-=f;
60             a[i^1].v+=f;
61             if(!al)break;
62         }
63     }
64     if(!fl)d[x]=-1;
65     return fl;
66 }
67 int main()
68 {
69     scanf("%d%d",&m,&n);
70     s=0,t=m*n+1;
71     int sum=0;
72     for(int i=1;i<=m;++i)
73     for(int j=1;j<=n;++j)
74     {
75         scanf("%d",&tu[i][j]);
76         sum+=tu[i][j];
77     }
78     memset(num,-1,sizeof(num));
79     int tim=0;
80     for(int i=1;i<=m;++i)
81     for(int j=1;j<=n;++j)
82     num[i][j]=++tim;
83     for(int i=1;i<=m;++i)
84     for(int j=1;j<=n;++j)
85     if((i+j)%2==0)con(num[i][j],t,tu[i][j]);
86     else
87     {
88         con(s,num[i][j],tu[i][j]);
89         con(num[i][j],num[i-1][j],INF);
90         con(num[i][j],num[i+1][j],INF);
91         con(num[i][j],num[i][j-1],INF);
92         con(num[i][j],num[i][j+1],INF);
93     }
94     int ans=0;
95     while(bfs())ans+=dfs(s,INF);
96     cout<<sum-ans;
97     return 0;
98 }
View Code

 

 
posted @ 2018-07-12 15:29  qwertaya  阅读(201)  评论(0编辑  收藏  举报
MDZX
Changsha
Fulan