相邻格不能同时选,通过黑白染色把相邻格染成不同色,构成一个二分图。
由s向所有白点连接一条容量为wij的边,由黑点向t连接容量为wij的边,白点向相邻黑点点容量为INF的边,不能选相邻格即不能让s-t联通,问题转化为求s-t最小割,即最大流。
// q.c #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #define mem(a) memset(a,0,sizeof(a)) using namespace std; const int M=35,INF=(int)1e8; struct Edge { int v,nex,flow,cap; Edge() {} Edge(int a,int b,int c,int d):v(a),nex(b),flow(c),cap(d) {} }ed[M*M<<4]; int cnt,head[M*M]; void add_edge(int a,int b,int c) { ed[cnt]=Edge(b,head[a],0,c); head[a]=cnt++; ed[cnt]=Edge(a,head[b],0,0); head[b]=cnt++; } struct Dinic { int n,s,t,dis[M*M],cur[M*M]; queue<int> Q; Dinic():n(0),s(0),t(0) { mem(dis); mem(cur); for(;!Q.empty();Q.pop()); } bool bfs() { mem(dis); dis[s]=1; Q.push(s); int u,i; Edge e; while(!Q.empty()) { u=Q.front(); Q.pop(); for(i=head[u];i!=-1;i=ed[i].nex) { e=ed[i]; if(!dis[e.v]&&e.cap>e.flow) { dis[e.v]=dis[u]+1; Q.push(e.v); } } } return dis[t]; } int dfs(int u,int lim) { if(u==t||!lim) return lim; int f=0,tmp=0; Edge e; for(int &i=cur[u];i!=-1;i=ed[i].nex) { e=ed[i]; if(dis[e.v]==dis[u]+1) { f=dfs(e.v,min(lim,e.cap-e.flow)); if(f>0) { ed[i].flow+=f; tmp+=f; ed[i^1].flow-=f; lim-=f; if(!lim) break; } } } return tmp; } int solve(int x,int y,int z) { s=x; t=y; n=z; int ans=0; for(;bfs();ans+=dfs(s,INF)) for(int i=0;i<=n;i++) cur[i]=head[i]; return ans; } }DC; int w[M][M],co[M][M],id[M][M]; int main() { freopen("grid.in","r",stdin); freopen("grid.out","w",stdout); memset(head,-1,sizeof(head)); int m,n,sum=0,tot=0; scanf("%d%d",&m,&n); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) { scanf("%d",&w[i][j]); sum+=w[i][j]; id[i][j]=++tot; (j==1)?(co[i][j]=co[i-1][j]^1):(co[i][j]=co[i][j-1]^1); } for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) { if(co[i][j]) { add_edge(0,id[i][j],w[i][j]); if(i-1>=1) add_edge(id[i][j],id[i-1][j],INF); if(j-1>=1) add_edge(id[i][j],id[i][j-1],INF); if(j+1<=n) add_edge(id[i][j],id[i][j+1],INF); if(i+1<=m) add_edge(id[i][j],id[i+1][j],INF); } else add_edge(id[i][j],tot+1,w[i][j]); } printf("%d\n",sum-DC.solve(0,tot+1,tot+1)); return 0; }