1. 程式人生 > >【COGS 2051】王者之劍 最小割

【COGS 2051】王者之劍 最小割

ret turn include div sizeof set urn har 中間

這個其實就是在說明相鄰的點不能取,我們發現只要其滿足這個條件他總能走出來,那麽我們就最小割就是了,我們先黑白染色,S 一排黑點 一排白點 T 對於相鄰的點我們就直接中間連INF,於是就滿足只要一個點選了,另一個點就不能選,我們跑完最小割就得到了滿足相鄰的點要麽都選要麽只選一方的最下舍棄。

#include <cstdio>
#include <cstring>
#define r register
#define Inf 0x7f7f7f7f
using namespace std;
inline int read()
{
   r int sum=0;
   r char
ch=getchar(); while(ch<0||ch>9)ch=getchar(); while(ch>=0&&ch<=9) { sum=(sum<<1)+(sum<<3)+ch-0; ch=getchar(); } return sum; } int a[105][105],S,T,n,m; struct Via { int to,next,f; }c[200000]; int head[100000],t=1; inline void add(int x,int y,int z) { c[
++t].to=y; c[t].f=z; c[t].next=head[x]; head[x]=t; } inline int Min(int x,int y) { return x<y?x:y; } int q[20000],top,tail,deep[20000]; inline bool bfs() { memset(deep,0,sizeof(deep)); deep[S]=top=tail=1,q[1]=S; while(top<=tail) { r int x=q[top++]; if(x==T)return 1; for(r int
i=head[x];i;i=c[i].next) if(c[i].f&&deep[c[i].to]==0) { deep[c[i].to]=deep[x]+1; q[++tail]=c[i].to; } } return 0; } int dfs(int x,int v) { if(x==T||!v)return v; r int ret=0; for(r int i=head[x];i;i=c[i].next) if(c[i].f&&deep[c[i].to]==deep[x]+1) { r int f=dfs(c[i].to,Min(v,c[i].f)); v-=f,ret+=f,c[i].f-=f,c[i^1].f+=f; if(!v)break; } if(!ret)deep[x]=0; return ret; } inline int dinic() { r int ans=0; while(bfs())ans+=dfs(S,Inf); return ans; } int main() { freopen("Excalibur.in","r",stdin); freopen("Excalibur.out","w",stdout); n=read(),m=read(); r int ans=0; S=n*m+1,T=S+1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { a[i][j]=read(),ans+=a[i][j]; if((i+j)&1) { add(S,(i-1)*m+j,a[i][j]),add((i-1)*m+j,S,0); if(i!=1)add((i-1)*m+j,(i-2)*m+j,Inf),add((i-2)*m+j,(i-1)*m+j,0); if(j!=1)add((i-1)*m+j,(i-1)*m+j-1,Inf),add((i-1)*m+j-1,(i-1)*m+j,0); if(i!=n)add((i-1)*m+j,i*m+j,Inf),add(i*m+j,(i-1)*m+j,0); if(j!=m)add((i-1)*m+j,(i-1)*m+j+1,Inf),add((i-1)*m+j+1,(i-1)*m+j,0); } else { add((i-1)*m+j,T,a[i][j]),add(T,(i-1)*m+j,0); } } printf("%d",ans-dinic()); }

【COGS 2051】王者之劍 最小割