[ZJOI2009]狼和羊的故事——最大流

AubRain

2018-11-27 16:54:48

Solution

其实这题根本没有其它题解说的那么复杂。 建图方式: 1、原点向所有狼连流量 $inf$ 的边 2、所有羊向汇点连流量 $inf$ 的边 3、所有点向四周连流量为 $1$ 的边。 然后下面就没了。 求出最小割就是答案,不用考虑题解说的什么 $0$ 的归属问题。 为什么是对的? 所有狼和羊之间的边都被割掉了,相当于修了栅栏,所以是对的。 ~~死因:n,m写反调了一个小时~~ ```cpp #include<bits/stdc++.h> #define N 100005 #define INF 1<<29 #define num(i,j) ((i-1)*m+j) using namespace std; inline void rd(int &X){ X=0;int w=0;char ch=0; while(!isdigit(ch))w|=ch=='-',ch=getchar(); while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); X=w?-X:X; } int n,m,s,t,ans,f,k; int head[N],cnt=1,d[N]; struct nd{int nxt,to,v;}e[N<<1]; #define For(x) for(int y,i=head[x];(y=e[i].to);i=e[i].nxt) void add(int x,int y,int w){ e[++cnt]=(nd){head[x],y,w};head[x]=cnt; e[++cnt]=(nd){head[y],x,0};head[y]=cnt; } bool bfs() { queue<int> q; q.push(s); memset(d,0,sizeof d); d[s]=1; while(!q.empty()){ int x=q.front();q.pop(); For(x) if(e[i].v&&!d[y]){ q.push(y); d[y]=d[x]+1; if(y==t) return 1; } } return 0; } int dinic(int x,int flow) { if(x==t) return flow; int re=flow; for(int y,i=head[x];(y=e[i].to)&&re;i=e[i].nxt) if(e[i].v&&d[y]==d[x]+1) { k=dinic(y,min(re,e[i].v)); if(!k) d[y]=0; e[i].v-=k;e[i^1].v+=k;re-=k; } return flow-re; } int a[105][105]; int mx[]={1,-1,0,0}; int my[]={0,0,1,-1}; void build() { rd(n);rd(m);s=n*m+1;t=n*m+2; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) rd(a[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(a[i][j]==1) add(s,num(i,j),INF); else if(a[i][j]==2) add(num(i,j),t,INF); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=0;k<4;k++) { int tx=i+mx[k]; int ty=j+my[k]; if(tx<=n and ty<=m and tx>=1 and ty>=1) add(num(i,j),num(tx,ty),1); } } int main() { build(); while(bfs()) while(f=dinic(s,INF)) ans+=f; cout<<ans; } ```