[ZJOI2009]狼和羊的故事

题目:BZOJ1412、洛谷P2598、Vijos P1555、codevs2351。

题目大意:有一个nm矩阵,每格里住着狼、羊或其他动物。现在要你建最少的篱笆,使得狼和羊分开。问最少建多长的篱笆。

解题思路:网络流最小割问题,求最大流即可。

首先建超级源点S=0,超级汇点T=nm+1。对于每只狼,从S到这只狼连接容量inf的边;对于每只羊,从这只羊到T连接容量inf的边。

然后,对于每个点,若该点不是羊,则从该点向它四个方向所有不是狼的点连接容量为1的边。

建完图后就是裸的最大流问题,用Dinic、ISAP等都可,EK应该也可。

我用的是Dinic。

C++ Code:

#include<stdio.h>
#include<cctype>
#include<vector>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
int n,m,level[30003],iter[30003],a[103][103];
struct edges{
    int to,cap,rev;
};
vector<edges>G[200003];
queue<int>q;
inline int readint(){
    int p=0;
    char c=getchar();
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())p=p*10+c-'0';
    return p;
}
inline void addedge(int from,int to,int cap){
    G[from].push_back((edges){to,cap,G[to].size()});
    G[to].push_back((edges){from,0,G[from].size()-1});
}
void bfs(int s){
    memset(level,-1,sizeof(level));
    level[s]=0;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=0;i<G[u].size();++i){
            edges& e=G[u][i];
            if(level[e.to]<0&&e.cap>0){
                level[e.to]=level[u]+1;
                q.push(e.to);
            }
        }
    }
}
int dfs(int u,int t,int f){
    if(u==t)return f;
    for(int& i=iter[u];i<G[u].size();++i){
        edges& e=G[u][i];
        if(e.cap>0&&level[e.to]>level[u]){
            int d=dfs(e.to,t,min(f,e.cap));
            if(d){
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}
int max_flow(int s,int t){
    int flow=0;
    while(1){
        bfs(s);
        if(level[t]<0)return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while(f=dfs(s,t,INF))flow+=f;
    }
}
int main(){
    memset(a,-1,sizeof a);
    n=readint(),m=readint();
    for(int i=1;i<=n;++i)
	for(int j=1;j<=m;++j)a[i][j]=readint();
    for(int i=1;i<=n;++i)
	for(int j=1;j<=m;++j){
    	if(a[i][j]==1)addedge(0,(i-1)*m+j,INF);else
    	if(a[i][j]==2)
    	addedge((i-1)*m+j,n*m+1,INF);
    	if(a[i][j]==2)continue;
    	if(a[i+1][j]==2||a[i+1][j]==0)addedge((i-1)*m+j,i*m+j,1);
    	if(a[i-1][j]==2||a[i-1][j]==0)addedge((i-1)*m+j,(i-2)*m+j,1);
    	if(a[i][j+1]==2||a[i][j+1]==0)addedge((i-1)*m+j,(i-1)*m+j+1,1);
    	if(a[i][j-1]==2||a[i][j-1]==0)addedge((i-1)*m+j,(i-1)*m+j-1,1);
    }
    printf("%d
",max_flow(0,n*m+1));
    return 0;
}
原文地址:https://www.cnblogs.com/Mrsrz/p/7612076.html