[Hdu 3046]Pleasant sheep and big big wolf

来源:互联网 发布:学生数据字典 样例 编辑:程序博客网 时间:2024/06/10 12:31

这道题目让我回忆起童年看喜羊羊和灰太狼的故事。。。
算了,说回正题,这道题就是n*m的方格,有些方格有羊在上面,有些方格有狼在上面,
现在就问,至少要建多少个栅栏才能让狼无法到达羊所在方格(栅栏可以建在一个方格的四条边上)

如下图就是一种处理方法:
这里写图片描述

这道题同样可以用最小割模型来描述,
这道题本质就是用割把羊和狼分开,求最小代价。
首先每个方格向它旁边的方格连一条边,长度为1,如果最小割经过这条边,就代表这条路不能走,也就是代表修栅栏的代价
很显然的首先要用源点连接狼所在方格,羊所在方格连接汇点
按题目意思,因为羊和狼不能被分为一个区域当中,所以权值为inf

然后再利用网络流最小流最大割定理就可以用最大流Dinic算法解决,
这里写图片描述

CalNum计算每个方格所对应的编号

#include <iostream>#include <cstdio>#include <cstring>#include <queue>using namespace std;#define inf 0x7fffffffstruct Edge{    int v,w,nxt;}g[400055];int head[400055];int work[400055];int cnt;void addEdge(int u,int v,int w){    g[cnt].v = v;    g[cnt].w = w;    g[cnt].nxt = head[u];    head[u] = cnt;    ++ cnt;} int n,m;int a;queue<int> q;int dis[400055];int flow,ans;int S,T;int CASES;inline int CalNum(int x,int y){    return (x-1)*m + y;}void init(){    cnt = flow = ans = 0;    memset(head,-1,sizeof(head));    memset(g,0,sizeof(g));}bool bfs(){    memset(dis,-1,sizeof(dis));    while(!q.empty()) q.pop();    dis[S] = 0;q.push(S);    while(!q.empty()){        int u = q.front();q.pop();        for(int i=head[u];i!=-1;i=g[i].nxt){            int v = g[i].v;            if((dis[v]==-1)&&(g[i].w>0)){                dis[v] = dis[u]+1;                q.push(v);            }        }    }    return (dis[T]!=-1);}int dfs(int u,int exp){    if(u==T) return exp;    int tmp = 0;    for(int &i=work[u];i!=-1;i=g[i].nxt){        int v = g[i].v;        if((dis[v]==dis[u]+1)&&(g[i].w>0)){            tmp = dfs(v,min(exp,g[i].w));            if(!tmp) continue;            g[i].w -= tmp;            g[i^1].w += tmp;            return tmp;        }    }    return 0;}int main(){    while(~scanf("%d%d",&n,&m)){        init();        S = 0; T = m*n+1;        for(int i=1;i<=n;++i){            for(int j=1;j<=m;++j){                scanf("%d",&a);                int tmp = CalNum(i,j);                if(a==1){                    addEdge(tmp,T,inf);                    addEdge(T,tmp,0);                }                if(a==2){                    addEdge(S,tmp,inf);                    addEdge(tmp,S,0);                }                if(i>1){                    addEdge(tmp,CalNum(i-1,j),1);                    addEdge(CalNum(i-1,j),tmp,0);                }                if(i<n){                    addEdge(tmp,CalNum(i+1,j),1);                    addEdge(CalNum(i+1,j),tmp,0);                }                if(j>1){                    addEdge(tmp,CalNum(i,j-1),1);                    addEdge(CalNum(i,j-1),tmp,0);                }                if(j<m){                    addEdge(tmp,CalNum(i,j+1),1);                    addEdge(CalNum(i,j+1),tmp,0);                }            }        }        while(bfs()){            memcpy(work,head,sizeof(head));            while(flow=dfs(S,inf)){                ans += flow;            }        }                printf("Case %d:\n%d\n",++CASES,ans);    }}