BZOJ_P1412 [ZJOI2009]狼和羊的故事(网络流+最大流最小割)

48 篇文章 0 订阅
23 篇文章 0 订阅

BZOJ传送门
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 2118 Solved: 1097
[Submit][Status][Discuss]
Description
“狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。 Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。

Input
文件的第一行包含两个整数n和m。接下来n行每行m个整数,1表示该格子属于狼的领地,2表示属于羊的领地,0表示该格子不是任何一只动物的领地。

Output
文件中仅包含一个整数ans,代表篱笆的最短长度。

Sample Input
2 2
2 2
1 1

Sample Output
2

数据范围
10%的数据 n,m≤3
30%的数据 n,m≤20
100%的数据 n,m≤100

HINT
Source

简单网络流,再打打Dinic的模板;
建模就是向四周连边,容量为1,建源建汇,源点连所有狼,容量为INF,汇点连所用羊,容量为INF,用最小割思想将二者分开即可

#include<cstdio>
#include<climits>
#include<cstring>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
#define N 10010
#define M 105
#define INF INT_MAX/3*2
struct NetWork{
    struct Edge{int fr,to,flow;};
    vector<Edge> edge;vector<int> g[N];
    int p[N],d[N],a[N],cur[N];bool b[N];
    int n,m,s,t,tot,flow;int be[M][M];

    inline int hash(int i,int j){return (i-1)*m+j;}

    void Add_Edge(int fr,int to,int flow){
        edge.push_back(Edge{fr,to,flow});
        edge.push_back(Edge{to,fr,0});tot=edge.size();
        g[fr].push_back(tot-2);g[to].push_back(tot-1);
    }
    bool bfs(){
        memset(d,-1,sizeof(d));memset(b,0,sizeof(b));
        queue<int> q;q.push(s);d[s]=0;b[s]=true;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=0;i<g[x].size();i++){
                Edge &e=edge[g[x][i]];
                if(e.flow>0&&!b[e.to]) d[e.to]=d[x]+1,b[e.to]=true,q.push(e.to);
            }
        }
        return b[t];
    }
    void MaxFlow(){
        flow=0;
        while(bfs()){
            int k=0,x=s;
            memset(cur,0,sizeof(cur));
            for(;;){
                if(x==t){
                    int mine=-1,minf=INF;
                    for(int i=0;i<k;i++)
                        if(edge[p[i]].flow<minf) mine=i,minf=edge[p[i]].flow;
                    for(int i=0;i<k;i++)
                        edge[p[i]].flow-=minf,edge[p[i]^1].flow+=minf;
                    k=mine,x=edge[p[mine]].fr,flow+=minf;
                }
                for(int &i=cur[x];i<g[x].size();i++){
                    Edge &e=edge[g[x][i]];
                    if(e.flow>0&&d[e.to]==d[x]+1) break;
                }
                if(cur[x]<g[x].size())
                    p[k++]=g[x][cur[x]],x=edge[p[k-1]].to;
                else
                    if(k==0) break;
                    else d[x]=-1,k--,x=edge[p[k]].fr;
            }
        }
    }
    inline int in(){
        int x=0;char ch=getchar();while(ch>'9'||ch<'0') ch=getchar();
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x;
    }
    void init(){
        scanf("%d%d",&n,&m);s=n*m+1,t=s+1;
        int dx[]={-1,0,1,0},dy[]={0,-1,0,1};
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                scanf("%d",&be[i][j]);
                if(be[i][j]==1) Add_Edge(s,hash(i,j),INF);
                if(be[i][j]==2) Add_Edge(hash(i,j),t,INF);
                for(int k=0;k<4;k++){
                    int x=i+dx[k],y=j+dy[k];
                    if(x>0&&y>0&&x<=n&&y<=m) Add_Edge(hash(i,j),hash(x,y),1);
                }
            }
        MaxFlow();printf("%d\n",flow);
    }
}s;
int main(){
    s.init();return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值