LuoguP2774 方格取数问题(最小割)

题目背景

none!

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

解题思路:

想个办法将选一个点和不选周围点关联起来。

那就是将其连到一条线上,这样变成了,想要割开源汇点,不割掉这个点,就要割掉相连的点。

这就变成了最小割,将棋盘和白染色,使与黑格相连的格都不是黑色。

源点与黑点连,黑点与临近点连,白点与汇点连。

跑最小割就好了。

代码:

  1 #include<queue>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 const int oo=0x3f3f3f3f;
  6 struct pnt{
  7     int hd;
  8     int lyr;
  9     int now;
 10 }p[10001];
 11 struct ent{
 12     int twd;
 13     int lst;
 14     int vls;
 15 }e[1000000];
 16 int cnt;
 17 int n,m;
 18 int s,t;
 19 int di[4]={0,0,1,-1};
 20 int dj[4]={1,-1,0,0};
 21 int no[101][101];
 22 int vo[101][101];
 23 std::queue<int>Q;
 24 void ade(int f,int t,int v)
 25 {
 26     cnt++;
 27     e[cnt].twd=t;
 28     e[cnt].vls=v;
 29     e[cnt].lst=p[f].hd;
 30     p[f].hd=cnt;
 31     return ;
 32 }
 33 bool Bfs(void)
 34 {
 35     while(!Q.empty())
 36         Q.pop();
 37     for(int i=1;i<=t;i++)
 38         p[i].lyr=0;
 39     p[s].lyr=1;
 40     Q.push(s);
 41     while(!Q.empty())
 42     {
 43         int x=Q.front();
 44         Q.pop();
 45         for(int i=p[x].hd;i;i=e[i].lst)
 46         {
 47             int to=e[i].twd;
 48             if(p[to].lyr==0&&e[i].vls>0)
 49             {
 50                 p[to].lyr=p[x].lyr+1;
 51                 if(to==t)
 52                     return true;
 53                 Q.push(to);
 54             }
 55         }
 56     }
 57     return false;
 58 }
 59 int Dfs(int x,int fll)
 60 {
 61     if(x==t)
 62         return fll;
 63     for(int& i=p[x].now;i;i=e[i].lst)
 64     {
 65         int to=e[i].twd;
 66         if(p[to].lyr==p[x].lyr+1&&e[i].vls>0)
 67         {
 68             int ans=Dfs(to,std::min(fll,e[i].vls));
 69             if(ans>0)
 70             {
 71                 e[i].vls-=ans;
 72                 e[((i-1)^1)+1].vls+=ans;
 73                 return ans;
 74             }
 75         }
 76     }
 77     return 0;
 78 }
 79 int Dinic(void)
 80 {
 81     int ans=0;
 82     while(Bfs())
 83     {
 84         for(int i=1;i<=t;i++)
 85             p[i].now=p[i].hd;
 86         int dlt;
 87         while(dlt=Dfs(s,oo))
 88             ans+=dlt;
 89     }
 90     return ans;
 91 }
 92 int main()
 93 {
 94 //    freopen("a.in","r",stdin);
 95     int sum=0;
 96     scanf("%d%d",&n,&m);
 97     for(int i=1;i<=n;i++)
 98     {
 99         for(int j=1;j<=m;j++)
100         {
101             scanf("%d",&vo[i][j]);
102             no[i][j]=++cnt;
103             sum+=vo[i][j];
104         }
105     }
106     s=n*m+1;
107     t=s+1;
108     cnt=0;
109     for(int i=1;i<=n;i++)
110     {
111         for(int j=1;j<=m;j++)
112         {
113             if((i+j)%2==0)
114             {
115                 ade(s,no[i][j],vo[i][j]);
116                 ade(no[i][j],s,0);
117                 for(int d=0;d<4;d++)
118                 {
119                     int ii=i+di[d],jj=j+dj[d];
120                     if(ii<=0||jj<=0||ii>n||jj>m)
121                         continue;
122                     ade(no[i][j],no[ii][jj],oo);
123                     ade(no[ii][jj],no[i][j],0);
124                 }
125             }else{
126                 ade(no[i][j],t,vo[i][j]);
127                 ade(t,no[i][j],0);
128             }
129         }
130     }
131     printf("%d\n",sum-Dinic());
132     return 0;
133 }

 

posted @ 2019-01-01 19:26  Unstoppable728  阅读(171)  评论(0编辑  收藏  举报