1. 程式人生 > >[ZJOI2009]狼和羊的故事

[ZJOI2009]狼和羊的故事

inf vector 分開 char using style rom urn str

題目: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\n",max_flow(0,n*m+1));
    return 0;
}

[ZJOI2009]狼和羊的故事