HDU 3046 Pleasant sheep and big big wolf(最小割)

Pleasant sheep and big big wolf

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2372    Accepted Submission(s): 989


Problem Description
In ZJNU, there is a well-known prairie. And it attracts pleasant sheep and his companions to have a holiday. Big big wolf and his families know about this, and quietly hid in the big lawn. As ZJNU ACM/ICPC team, we have an obligation to protect pleasant sheep and his companions to free from being disturbed by big big wolf. We decided to build a number of unit fence whose length is 1. Any wolf and sheep can not cross the fence. Of course, one grid can only contain an animal.
Now, we ask to place the minimum fences to let pleasant sheep and his Companions to free from being disturbed by big big wolf and his companions.

 

Input
There are many cases.
For every case:

N and M(N,M<=200)
then N*M matrix:
0 is empty, and 1 is pleasant sheep and his companions, 2 is big big wolf and his companions.
 

Output
For every case:

First line output “Case p:”, p is the p-th case;
The second line is the answer.
 

Sample Input
4 6 1 0 0 1 0 0 0 1 1 0 0 0 2 0 0 0 0 0 0 2 0 1 1 0
 

Sample Output
Case 1: 4
 

Source
 

题意:给一个n*m的巨阵,1:代表羊,2:代表狼。如今要用长为1的 篱笆去隔开狼与羊,问最少用多少根篱笆。

解题:最小割。建图:源点S=0,汇点T=n*m+1;狼与源点相连,边容INF,羊与汇点相连。边容INF。

其它相邻的点相连,边容为1。

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define captype int

const int MAXN = 40010;   //点的总数
const int MAXM = 400010;    //边的总数
const int INF = 1<<30;
struct EDG{
    int to,next;
    captype cap;
} edg[MAXM];
int eid,head[MAXN];
int gap[MAXN];  //每种距离(或可觉得是高度)点的个数
int dis[MAXN];  //每一个点到终点eNode 的最短距离
int cur[MAXN];  //cur[u] 表示从u点出发可流经 cur[u] 号边

void init(){
    eid=0;
    memset(head,-1,sizeof(head));
}
//有向边 三个參数。无向边4个參数
void addEdg(int u,int v,captype c,captype rc=0){
    edg[eid].to=v; edg[eid].next=head[u];
    edg[eid].cap=c; head[u]=eid++;

    edg[eid].to=u; edg[eid].next=head[v];
    edg[eid].cap=rc; head[v]=eid++;
}
//预处理eNode点到全部点的最短距离
void BFS(int sNode, int eNode){
    queue<int>q;
    memset(gap,0,sizeof(gap));
    memset(dis,-1,sizeof(dis));
    gap[0]=1;
    dis[eNode]=0;
    q.push(eNode);
    while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=head[u]; i!=-1; i=edg[i].next){
            int v=edg[i].to;
            if(dis[v]==-1){
                dis[v]=dis[u]+1;
                gap[dis[v]]++;
                q.push(v);
            }
        }
    }
}
int S[MAXN];    //路径栈,存的是边的id号
captype maxFlow_sap(int sNode,int eNode, int n){  //注意:n为点的总个数,包含源点与汇点
    BFS(sNode, eNode);              //预处理eNode到全部点的最短距离
    if(dis[sNode]==-1) return 0;    //源点到不可到达汇点
    memcpy(cur,head,sizeof(head));

    int top=0;  //栈顶
    captype ans=0;  //最大流
    int u=sNode;
    while(dis[sNode]<n){   //推断从sNode点有没有流向下一个相邻的点
        if(u==eNode){   //找到一条可增流的路
            captype Min=INF ;
            int inser;
            for(int i=0; i<top; i++)    //从这条可增流的路找到最多可增的流量Min
            if(Min>=edg[S[i]].cap){
                Min=edg[S[i]].cap;
                inser=i;
            }
            for(int i=0; i<top; i++){
                edg[S[i]].cap-=Min;
                edg[S[i]^1].cap+=Min;  //可回流的边的流量
            }
            ans+=Min;
            top=inser;  //从这条可增流的路中的流量瓶颈 边的上一条边那里是能够再增流的,所以仅仅从断流量瓶颈 边裁断
            u=edg[S[top]^1].to;  //流量瓶颈 边的起始点
            continue;
        }
        bool flag = false;  //推断是否能从u点出发可往相邻点流
        int v;
        for(int i=cur[u]; i!=-1; i=edg[i].next){
            v=edg[i].to;
            if(edg[i].cap>0 && dis[u]==dis[v]+1){
                flag=true;
                cur[u]=i;
                break;
            }
        }
        if(flag){
            S[top++] = cur[u];  //增加一条边
            u=v;
            continue;
        }
        //假设上面没有找到一个可流的相邻点,则改变出发点u的距离(也可觉得是高度)为相邻可流点的最小距离+1
        int Mind= n;
        for(int i=head[u]; i!=-1; i=edg[i].next)
        if(edg[i].cap>0 && Mind>dis[edg[i].to]){
            Mind=dis[edg[i].to];
            cur[u]=i;
        }
        gap[dis[u]]--;
        if(gap[dis[u]]==0) return ans;  //当dis[u]这样的距离的点没有了,也就不可能从源点出发找到一条增广流路径
                                        //由于汇点到当前点的距离仅仅有一种。那么从源点到汇点必定经过当前点。然而当前点又没能找到可流向的点。那么必定断流
        dis[u]=Mind+1;      //假设找到一个可流的相邻点,则距离为相邻点距离+1,假设找不到,则为n+1
        gap[dis[u]]++;
        if(u!=sNode) u=edg[S[--top]^1].to;  //退一条边

    }
    return ans;
}
int main(){
    int _cas=0,n,m,a;
    int dir[4][2]={0,1,0,-1,1,0,-1,0};
    while(scanf("%d%d",&n,&m)>0){
        int s=0,t=n*m+1;
        init();
        for(int i=0; i<n; i++)
        for(int j=0; j<m; j++){
            scanf("%d",&a);
            if(a==2)
                addEdg(s , i*m+j+1, INF);
            else if(a==1)
                addEdg(i*m+j+1,t , INF);
            int ti,tj;
            for(int e=0; e<4; e++){
                ti=i+dir[e][0];
                tj=j+dir[e][1];
                if(ti>=0&&ti<n&&tj>=0&&tj<m)
                    addEdg(i*m+j+1,ti*m+tj+1, 1);
            }
        }
        printf("Case %d:
%d
",++_cas,maxFlow_sap(s , t ,t+1));
    }
}


原文地址:https://www.cnblogs.com/jhcelue/p/7105840.html