• bzoj1412: [ZJOI2009]狼和羊的故事(最小割)


    传送门

    首先,考虑只有狼和羊怎么办。我们把源点向所有羊连边,容$inf$,所有狼向汇点连边,容$inf$,然后羊向周围所有的狼连边,容$1$。那么,只要求一个割就能把狼和羊给分开,求一个最小割就是答案

    那么考虑要怎么处理值为0的点

    我们假设在网络流图中有这么一条边$S->羊->0->狼->T$,为了使狼和羊分开,我们可能把空地划分给狼或给羊,那么在图中求最小割时,会割开的只有$羊->0$或$0->狼$这两条边,分别对应两种情况。那么,只要对于每个空地,我们从羊向它连边,从它向狼连边,那么在前面的基础上跑一个最小割就是答案了

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<queue>
     6 #define inf 0x3f3f3f3f
     7 using namespace std;
     8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     9 char buf[1<<21],*p1=buf,*p2=buf;
    10 inline int read(){
    11     #define num ch-'0'
    12     char ch;bool flag=0;int res;
    13     while(!isdigit(ch=getc()))
    14     (ch=='-')&&(flag=true);
    15     for(res=num;isdigit(ch=getc());res=res*10+num);
    16     (flag)&&(res=-res);
    17     #undef num
    18     return res;
    19 }
    20 const int N=10005,M=1000005;
    21 int head[N],Next[M],ver[M],edge[M],tot=1;
    22 int cur[N],dep[N],id[105][105],mp[105][105];
    23 int n,m,S,T;
    24 queue<int> q;
    25 int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
    26 inline void add(int u,int v,int e){
    27     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;
    28     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=0;
    29 }
    30 bool bfs(){
    31     memset(dep,-1,sizeof(dep));
    32     for(int i=S;i<=T;++i) cur[i]=head[i];
    33     while(!q.empty()) q.pop();
    34     q.push(S),dep[S]=0;
    35     while(!q.empty()){
    36         int u=q.front();q.pop();
    37         for(int i=head[u];i;i=Next[i]){
    38             int v=ver[i];
    39             if(edge[i]&&dep[v]<0){
    40                 dep[v]=dep[u]+1,q.push(v);
    41                 if(v==T) return true;
    42             }
    43         }
    44     }
    45     return false;
    46 }
    47 int dfs(int u,int limit){
    48     if(u==T||!limit) return limit;
    49     int flow=0,f;
    50     for(int &i=cur[u];i;i=Next[i]){
    51         int v=ver[i];
    52         if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,edge[i])))){
    53             flow+=f,limit-=f;
    54             edge[i]-=f,edge[i^1]+=1;
    55             if(!limit) break;
    56         }
    57     }
    58     return flow;
    59 }
    60 int dinic(){
    61     int flow=0;
    62     while(bfs()) flow+=dfs(S,inf);
    63     return flow;
    64 }
    65 void build(){
    66     for(int i=1;i<=n;++i)
    67     for(int j=1;j<=m;++j){
    68         if(!mp[i][j]) continue;
    69         (mp[i][j]&1)?add(id[i][j],T,inf):add(S,id[i][j],inf);
    70     }
    71     for(int i=1;i<=n;++i)
    72     for(int j=1;j<=m;++j){
    73         if(mp[i][j]&1) continue;
    74         for(int k=0;k<4;++k){
    75             int xx=i+dx[k],yy=j+dy[k];
    76             if(xx<1||xx>n||yy<1||yy>m||(mp[xx][yy]&2)) continue;
    77             add(id[i][j],id[xx][yy],1);
    78         }
    79     }
    80 }
    81 int main(){
    82 //    freopen("testdata.in","r",stdin);
    83     n=read(),m=read();
    84     for(int i=1;i<=n;++i)
    85     for(int j=1;j<=m;++j)
    86     mp[i][j]=read(),id[i][j]=(i-1)*m+j;
    87     S=0,T=n*m+1;
    88     build();
    89     printf("%d
    ",dinic());
    90     return 0;
    91 }
  • 相关阅读:
    006使用python编写一个猜数字的程序
    002python函数、高级特性
    008python绘制五个五角星
    005使用 Python 生成 200 个激活码
    001python基础
    003python函数式编程,模块
    004python面向对象,错误,调试和测试
    Docker系列之(一):10分钟玩转Docker
    mongoDB系列之(一):10分钟玩转mongoDB
    Hadoop系列之(二):Hadoop集群部署
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9623002.html
Copyright © 2020-2023  润新知