[网络流24题] 方格取数问题

题面:

传送门

思路:

相邻的点不能同时取,那么在这个图中,实际上分了两种格子,每种格子相互之间随便取

那么就是二分图了

把相邻的点之间连边,得到一个二分图,我们实际上就是要求这个图的带权最大独立集

于是这道题转化为二分图问题,而二分图中最大独立集等于全集减去最小点覆盖,最小点覆盖等于这个图的最大匹配(都带权)

那么用网络流做就好了

将这个平面上的方格像国际象棋那样黑白染色

源点连黑点,容量为黑点权值

黑点连白点,容量为inf

白点连汇点,容量为白点权值

跑S-T最大流(即S-T最小割),用所有点的权值和减去最大流值,就得到了答案

因为在这个建好的网络流图里面,最大流等于最小割等于最小点覆盖

Code:

建图比较丑,请见谅

 1     #include<iostream>
 2     #include<cstdio>
 3     #include<cstring>
 4     #include<algorithm>
 5     #define inf 0x7fffffff
 6     using namespace std;
 7     inline int read(){
 8         int re=0,flag=1;char ch=getchar();
 9         while(ch>'9'||ch<'0'){
10             if(ch=='-') flag=-1;
11             ch=getchar();
12         }
13         while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
14         return re*flag;
15     }
16     inline int _min(int l,int r){return (l>r)?r:l;}
17     const int dx[5]={0,-1,0,1,0},dy[5]={0,0,-1,0,1};
18     int n,m,cnt=-1,ans,x[50][50],first[2500],dep[2500],cur[2500];
19     struct edge{
20         int to,next,w;
21     }a[500010];
22     inline void add(int u,int v,int w){
23     //    cout<<"add "<<u<<ends<<v<<ends<<w<<endl;
24         a[++cnt].to=v;a[cnt].next=first[u];first[u]=cnt;a[cnt].w=w;
25         a[++cnt].to=u;a[cnt].next=first[v];first[v]=cnt;a[cnt].w=0;
26     }
27     inline bool bfs(int s,int t){
28         int q[2500],head=0,tail=1,i,u,v;
29         for(i=s;i<=t;i++) dep[i]=inf,cur[i]=first[i];
30         q[0]=s;dep[s]=0;
31         while(head<tail){
32             u=q[head++];
33     //        cout<<"bfs "<<u<<ends<<dep[u]<<ends<<head<<ends<<tail<<endl;
34             for(i=first[u];~i;i=a[i].next){
35                 v=a[i].to;
36                 if(!a[i].w||dep[v]!=inf) continue;
37     //            cout<<"to "<<v<<endl;
38                 dep[v]=dep[u]+1;
39                 q[tail++]=v;
40             }
41     //        system("pause");
42         }
43         return dep[t]!=inf;
44     }
45     int dfs(int u,int t,int low){
46     //    cout<<"dfs "<<u<<ends<<t<<ends<<low<<endl;
47         if(u==t||!low) return low;
48         int flow=0,f,i,v;
49         for(i=cur[u];~i;i=a[i].next){
50             cur[u]=i;v=a[i].to;
51             if(dep[v]==dep[u]+1&&(f=dfs(v,t,_min(low,a[i].w)))){
52     //            cout<<"in "<<u<<" return from "<<v<<ends<<f<<endl;
53                 flow+=f;low-=f;
54                 a[i].w-=f;a[i^1].w+=f;
55                 if(!low) break;
56             }
57         }
58     //    cout<<"return "<<u<<ends<<t<<ends<<low<<ends<<flow<<endl;
59         return flow;
60     }
61     void dinic(){
62         while(bfs(0,n*m+1)) ans+=dfs(0,n*m+1,inf);
63     }
64     int main(){
65         freopen("grid.in","r",stdin);
66         freopen("grid.out","w",stdout);
67         memset(first,-1,sizeof(first));
68         int i,j,k,ti,tj;
69         n=read();m=read();
70         for(i=1;i<=n;i++) for(j=1;j<=m;j++) x[i][j]=read(),ans-=x[i][j];
71         for(i=1;i<=n;i++){
72             for(j=1;j<=m;j++){
73                 if((i+j)&1) add((i-1)*m+j,n*m+1,x[i][j]);
74                 else add(0,(i-1)*m+j,x[i][j]);
75                 if((i+j)&1) continue;
76                 for(k=1;k<=4;k++){
77                     ti=i+dx[k];tj=j+dy[k];
78                     if(ti<1||ti>n||tj<1||tj>m) continue;
79                     add((i-1)*m+j,(ti-1)*m+tj,inf);
80                 }
81             }
82         }
83         dinic();
84         printf("%d",-ans);
85     }
原文地址:https://www.cnblogs.com/dedicatus545/p/8454337.html