BZOJ 1412 狼和羊的故事

Posted on 2015-12-15 23:23  ziliuziliu  阅读(172)  评论(0编辑  收藏  举报

这个妥妥的最小割,但是我想了好久。。。。

考虑所有羊连源点,狼连汇点,相邻点两边跑最小割(最大流)即可。

正确性?考虑类似一个二分图的东西,我们只需要把狼集合和羊集合拦腰斩断即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxe 100005
#define maxv 10011
#define inf 1234567
#define s 0
#define t 10010
using namespace std;
int n,m,map[105][105],dx[]={0,0,1,0,-1},dy[]={0,1,0,-1,0};
int dis[maxv],g[maxv],nume=1;
struct edge
{
int v,f,nxt;
}e[maxe];
void addedge(int u,int v,int flow)
{
e[++nume].v=v;
e[nume].nxt=g[u];
e[nume].f=flow;
g[u]=nume;
e[++nume].v=u;
e[nume].nxt=g[v];
e[nume].f=0;
g[v]=nume;
}
void build()
{
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
if (map[i][j]==1) addedge(s,(i-1)*m+j,inf);
else if (map[i][j]==2) addedge((i-1)*m+j,t,inf);
for (int k=1;k<=4;k++)
{
int tx=i+dx[k],ty=j+dy[k];
if ((tx>=1) && (tx<=n) && (ty>=1) && (ty<=m))
addedge((i-1)*m+j,(tx-1)*m+ty,1);
}
}
}
bool bfs()
{
memset(dis,-1,sizeof(dis));
queue <int> q;
q.push(s);
dis[s]=0;
while (!q.empty())
{
int head=q.front();
q.pop();
for (int i=g[head];i;i=e[i].nxt)
{
if ((e[i].f>0) && (dis[e[i].v]<0))
{
dis[e[i].v]=dis[head]+1;
q.push(e[i].v);
}
}
}
if (dis[t]==-1) return false;
return true;
}
int dinic(int x,int low)
{
if (x==t) return low;
int ret=0;
for (int i=g[x];low && i;i=e[i].nxt)
{
if ((e[i].f!=0) && (dis[e[i].v]==dis[x]+1))
{
int dd=dinic(e[i].v,min(low,e[i].f));
low=low-dd;
ret=ret+dd;
e[i].f=e[i].f-dd;
e[i^1].f=e[i^1].f+dd;
}
}
if (ret==0) dis[x]=-1;
return ret;
}
int main()
{
memset(map,0,sizeof(map));
memset(g,0,sizeof(g));
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%d",&map[i][j]);
build();
int ans=0;
while (bfs()==true)
ans=ans+dinic(s,inf);
printf("%d\n",ans);
return 0;
}