BZOJ 1412: [ZJOI2009]狼和羊的故事【最小割】

1412: [ZJOI2009]狼和羊的故事

【题目描述】
传送门

【题解】

典型的最小割,那么怎么建图呢?
首先肯定要建超级源和汇,然后肯定狼向羊建边(反过来也可以),若有空的的话就是(狼->空->空->羊)按照这个顺序建边就可以了。

代码如下

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int flg[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
int hd,tl,n,m,a[105][105],S,T,dep[10005],que[10005];
int tot=-1,lnk[10005],nxt[2*40005],son[2*40005],W[2*40005];
void add(int x,int y,int w){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;W[tot]=w;}
int CHG(int x,int y){return (x-1)*m+y;}
bool check(int x,int y){if(x<1||x>n||y<1||y>m) return 0;return 1;}
bool BFS(){
    memset(dep,0,sizeof(dep));dep[S]=1;
    hd=0,que[tl=1]=S;
    while(hd!=tl){
        int x=que[++hd];
        for(int j=lnk[x];j^-1;j=nxt[j])
        if(!dep[son[j]]&&W[j]>0) dep[son[j]]=dep[x]+1,que[++tl]=son[j];
    }
    return dep[T];
}
int DFS(int x,int flow){
    if(x==T) return flow;
    int now=0;
    for(int j=lnk[x];j^-1;j=nxt[j])
    if((dep[son[j]]==dep[x]+1)&&W[j]>0){
        int y=DFS(son[j],min(flow,W[j]));
        if(y>0){W[j]-=y;W[j^1]+=y;now+=y;if(now==flow) return flow;}
    }
    if(!now) dep[x]=0;
    return now;
}
int Dinic(){
    int ans=0;
    while(BFS())
    while(int t=DFS(S,1e9)) ans+=t;
    return ans;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("prob.in","r",stdin);
    freopen("prob.out","w",stdout);
    #endif
    scanf("%d%d",&n,&m);S=0,T=n*m+1; 
    memset(lnk,-1,sizeof(lnk));
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++){
        scanf("%d",&a[i][j]);
        if(a[i][j]==2) add(S,CHG(i,j),1e9),add(CHG(i,j),S,0);
        if(a[i][j]==1) add(CHG(i,j),T,1e9),add(T,CHG(i,j),0);
    }
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    for(int k=0;k<4;k++)
    if(check(i+flg[k][0],j+flg[k][1])){
        if(a[i][j]==2&&a[i+flg[k][0]][j+flg[k][1]]==1)
        add(CHG(i,j),CHG(i+flg[k][0],j+flg[k][1]),1),add(CHG(i+flg[k][0],j+flg[k][1]),CHG(i,j),0);
        if(a[i][j]==2&&a[i+flg[k][0]][j+flg[k][1]]==0)
        add(CHG(i,j),CHG(i+flg[k][0],j+flg[k][1]),1),add(CHG(i+flg[k][0],j+flg[k][1]),CHG(i,j),0);
        if(a[i][j]==0&&a[i+flg[k][0]][j+flg[k][1]]==0)
        add(CHG(i,j),CHG(i+flg[k][0],j+flg[k][1]),1),add(CHG(i+flg[k][0],j+flg[k][1]),CHG(i,j),0);
        if(a[i][j]==0&&a[i+flg[k][0]][j+flg[k][1]]==1)
        add(CHG(i,j),CHG(i+flg[k][0],j+flg[k][1]),1),add(CHG(i+flg[k][0],j+flg[k][1]),CHG(i,j),0);
    }

    printf("%d\n",Dinic());
    return 0;
}

转载于:https://www.cnblogs.com/XSamsara/p/9190117.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值