[CODEVS 1907]方格取数 3

【问题描述】

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

【输入】

  第1行有2个正整数m和n,分别表示棋盘的行数和列数。

  接下来的m行,每行有n个正整数,表示棋盘方格中的数。

【输出】

  将取数的最大总和输出。

【算法分析】

  自从理解最大流之后,sjj118的最大流算法代码已经成为模板了。

  对整个矩阵进行黑白染色,每个黑点分别指向相邻的白点,容量为+∞,建立超级源节点s指向所有黑点,容量为a[i][j];建立超级汇点t使所有白点指向它,容量亦为a[i][j]。

  计算新图的最小割,此时图中不存在路径s~t,也就是不存在相邻两格的数,并且保证剩余有限容量边的容量总和最大。

  所以答案就是上述的容量总和,输出sum-maxflow即可。

【程序代码】

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define maxn 10000
 4 #define inf 1000000
 5 using namespace std;
 6 int n,m,a[40][40],ans=0,num=0;
 7 struct graph{
 8     int start,end,pointsize,tot;
 9     int c[maxn<<1],to[maxn<<1],next[maxn<<1],head[maxn],dis[maxn],nowhead[maxn];
10     void addedge(int a,int b,int l){
11         c[++tot]=l;to[tot]=b;next[tot]=head[a];head[a]=tot;
12         c[++tot]=0;to[tot]=a;next[tot]=head[b];head[b]=tot;
13     }
14     int q[maxn],ql,qr;
15     bool BFS(){
16         for (int i=1;i<=pointsize;++i) nowhead[i]=head[i],dis[i]=0;
17         ql=1; qr=0; q[++qr]=end;
18         while (ql<=qr){
19             for (int k=q[ql++],p=head[k];p;p=next[p])
20                 if(c[p^1]&&!dis[to[p]]&&to[p]!=end) dis[q[++qr]=to[p]]=dis[k]+1;
21         }
22         return dis[start];
23     }
24     int DFS(int k,int maxflow){
25         if (k==end) return maxflow;
26         int flow=0,tflow;
27         for (int&p=nowhead[k];p&&maxflow;p=next[p])
28             if(c[p]&&dis[to[p]]+1==dis[k]&&(tflow=DFS(to[p],min(maxflow,c[p]))))
29                 c[p]-=tflow,c[p^1]+=tflow,maxflow-=tflow,flow+=tflow;
30         return flow;
31     }
32     int dinic(int a,int b){
33         int flow=0;
34         start=a; end=b;
35         while (BFS()) flow+=DFS(a,inf);
36         return flow;
37     }    
38     graph(){
39         tot=1;
40     }
41 } G;
42 int main(){
43     scanf("%d%d",&m,&n);
44     G.pointsize=m*n+2;
45     for (int i=1;i<=m;++i)
46     for (int j=1;j<=n;++j){
47         scanf("%d",&a[i][j]);
48         ans+=a[i][j];
49     }
50     for (int i=1;i<=m;++i)
51     for (int j=1;j<=n;++j)
52     if ((i+j)%2==0)    {
53         if (j+1<=n) G.addedge((i-1)*n+j,(i-1)*n+j+1,inf);
54         if (i+1<=m) G.addedge((i-1)*n+j,i*n+j,inf);
55         if (j-1>=1) G.addedge((i-1)*n+j,(i-1)*n+j-1,inf);
56         if (i-1>=1) G.addedge((i-1)*n+j,(i-2)*n+j,inf);
57     }
58     for (int i=1;i<=m;++i)
59     for (int j=1;j<=n;++j)
60         if ((i+j)%2==0)    G.addedge(m*n+1,(i-1)*n+j,a[i][j]);
61         else G.addedge((i-1)*n+j,m*n+2,a[i][j]);
62     printf("%d",ans-G.dinic(m*n+1,m*n+2));
63     return 0;
64 }

声明:本博文为博主原创博文,未经允许请勿转载。

你可能感兴趣的:([CODEVS 1907]方格取数 3)