网络流Dinic算法
狼为源点,羊为汇点。
把每个源点连接到一点大源点上,容量为无穷。
把每个汇点连接到一点大汇点上,容量为无穷。
求出的最大流=最小割=答案。
#include <iostream>
#include<cstdio>
#include<cstring>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
const int maxint=1000001;
#define maxn 40008
int s,t;
struct edgee
{
int from,to,cap,flow;
};
vector<edgee> edges;
vector<int> G[maxn];
bool vis[maxn];
int dist[maxn];
int cur[maxn];
void add(int from,int to,int cap)
{
edges.push_back((edgee){from,to,cap,0});
edges.push_back((edgee){to,from,cap,0});
int k=edges.size();
G[from].push_back(k-2);//奇数为正向弧
G[to].push_back(k-1);
}
int max(int a,int b)
{
return a>b?a:b;
}
int min(int a,int b)
{
return a<b?a:b;
}
bool bfs()
{
memset(vis,0,sizeof(vis));
queue<int> q;
dist[s]=0;
vis[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
int sz=G[u].size();
for(int i=0;i<sz;i++)
{
edgee& e=edges[G[u][i]];
if(!vis[e.to] && e.cap>e.flow)
{
vis[e.to]=1;
dist[e.to]=dist[u]+1;
q.push(e.to);
}
}
}
return vis[t];
}
int dfs(int u,int low)
{
if(u==t || low==0)
return low;
int flow=0,sz=G[u].size(),d;//&引用的妙用
for(int& i=cur[u];i<sz;i++) //正在考虑的最后一条边开始考虑(效率关键)
{
edgee& e=edges[G[u][i]];
if( dist[u]+1==dist[e.to] && (d=dfs(e.to,min(e.cap-e.flow,low)))>0 )
{
e.flow+=d;
edges[G[u][i]^1].flow-=d;
flow+=d;
low-=d;
if(low==0)
break;
}
}
return flow;
}
int Dinic()
{
int flow=0;
while(bfs())
{
memset(cur,0,sizeof(cur));
flow+=dfs(s,maxint);
}
return flow;
}
int main()
{
int i,j;
int flag=1;
int n,m;
while(~scanf("%d%d",&n,&m))
{
edges.clear();
for(i=0;i<maxn;i++)
G[i].clear();
s=40002,t=40003;
for(i=0;i<n;i++)
{
int k;
for(j=0;j<m;j++)
{
scanf("%d",&k);
if(k==0)
{
if(j!=m-1)
add(i*m+j,i*m+j+1,1);
}
else
{
if(k==2)
{
if(j!=m-1)
{
add(i*m+j,i*m+j+1,1);
}
add(s,i*m+j,10001);
}
else
if(k==1)
{
if(j!=m-1)
{
add(i*m+j,i*m+j+1,1);
}
add(i*m+j,t,10001);
}
}
}
}
for(j=0;j<m;j++)
for(i=0;i<n-1;i++)
{
add((i)*m+j,(i+1)*m+j,1);
}
int temp=Dinic();
printf("Case %d:\n%d\n",flag++,temp);
}
return 0;
}