您的位置:首页 > 理论基础 > 计算机网络

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

2018-02-19 20:18 330 查看
题面:

传送门

思路:

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

那么就是二分图了

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

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

那么用网络流做就好了

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

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

黑点连白点,容量为inf

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

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

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

Code:

建图比较丑,请见谅

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 0x7fffffff
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') flag=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
inline int _min(int l,int r){return (l>r)?r:l;}
const int dx[5]={0,-1,0,1,0},dy[5]={0,0,-1,0,1};
int n,m,cnt=-1,ans,x[50][50],first[2500],dep[2500],cur[2500];
struct edge{
int to,next,w;
}a[500010];
inline void add(int u,int v,int w){
//    cout<<"add "<<u<<ends<<v<<ends<<w<<endl;
a[++cnt].to=v;a[cnt].next=first[u];first[u]=cnt;a[cnt].w=w;
a[++cnt].to=u;a[cnt].next=first[v];first[v]=cnt;a[cnt].w=0;
}
inline bool bfs(int s,int t){
int q[2500],head=0,tail=1,i,u,v;
for(i=s;i<=t;i++) dep[i]=inf,cur[i]=first[i];
q[0]=s;dep[s]=0;
while(head<tail){
u=q[head++];
//        cout<<"bfs "<<u<<ends<<dep[u]<<ends<<head<<ends<<tail<<endl;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;
if(!a[i].w||dep[v]!=inf) continue;
//            cout<<"to "<<v<<endl;
dep[v]=dep[u]+1;
q[tail++]=v;
}
//        system("pause");
}
return dep[t]!=inf;
}
int dfs(int u,int t,int low){
//    cout<<"dfs "<<u<<ends<<t<<ends<<low<<endl;
if(u==t||!low) return low;
int flow=0,f,i,v;
for(i=cur[u];~i;i=a[i].next){
cur[u]=i;v=a[i].to;
if(dep[v]==dep[u]+1&&(f=dfs(v,t,_min(low,a[i].w)))){
//            cout<<"in "<<u<<" return from "<<v<<ends<<f<<endl;
flow+=f;low-=f;
a[i].w-=f;a[i^1].w+=f;
if(!low) break;
}
}
//    cout<<"return "<<u<<ends<<t<<ends<<low<<ends<<flow<<endl;
return flow;
}
void dinic(){
while(bfs(0,n*m+1)) ans+=dfs(0,n*m+1,inf);
}
int main(){
freopen("grid.in","r",stdin);
freopen("grid.out","w",stdout);
memset(first,-1,sizeof(first));
int i,j,k,ti,tj;
n=read();m=read();
for(i=1;i<=n;i++) for(j=1;j<=m;j++) x[i][j]=read(),ans-=x[i][j];
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
if((i+j)&1) add((i-1)*m+j,n*m+1,x[i][j]);
else add(0,(i-1)*m+j,x[i][j]);
if((i+j)&1) continue;
for(k=1;k<=4;k++){
ti=i+dx[k];tj=j+dy[k];
if(ti<1||ti>n||tj<1||tj>m) continue;
add((i-1)*m+j,(ti-1)*m+tj,inf);
}
}
}
dinic();
printf("%d",-ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: