• POJ 3436 ACM Computer Factory 【网络流】【北大ACM/ICPC竞赛训练】


    我ac掉网络流的第一题!

    先总结一下网络流的一些算法吧,首先是Ford-Fulkerson算法,这个算法是保证了众多网络流算法的【正确性】,其他算法也是基于其【优化】得到的。Ford的算法在于引入“反向边”的概念,反向边就是反悔边,代表你给修正以前走了的边一个机会。为什么反向边是对的呢,凭空加进来一条边真的大丈夫吗,关于这个有相关正确性的证明,我也说不清楚只能直觉上去理解。

    之后是Edmonds-Karp即最短增广路算法,顾名思义,每次都找到达汇点边数最少的增广路,由此避免一些特定的消耗时间的情况。

    然后是我现在用的Dinic算法,它的优化在于之前的两次算法都是每次找一条增广路,但实际上我们可以一次找【多条增广路】,所以手工写deque加回溯又可以进一步缩小时间复杂度。

    一道网络流的题出的好不好,在于一眼能不能让选手看出是网络流模型。这道题我觉得出的蛮好的,把每个machine的input和output当作点去建边,就可以了。(input编号就是机器编号,output编号是其input编号加n,这样就可以把每个点标示出来了,其中一个input到另一个input或output到另一个output没有意义,所以就是0)

      1 #include<iostream>
      2 #include<cmath>
      3 #include<vector>
      4 #include<queue>
      5 #include<deque>
      6 #include<cstring>
      7 #define INF 1000000000
      8 using namespace std;
      9 
     10 int n,p;
     11 struct node{
     12     int in[12],out[12];
     13     int flow;
     14     node(int f1=0): flow(f1) {
     15         memset(in,0,sizeof(in));
     16         memset(out,0,sizeof(out));
     17     }
     18 }machine[110];
     19 int G[105][105],G2[105][105],layer[110];//G2是残余网络
     20 struct node1{
     21     int from,to,vol;
     22     node1(int i1=0,int j1=0,int v1=0): from(i1),to(j1),vol(v1) {}
     23 };
     24 vector<node1> ans;
     25 
     26 bool ok(int a,int b){//从a的output输送到b的input 
     27     for(int i=1;i<=p;i++){
     28         if( machine[a].out[i]==machine[b].in[i] || machine[b].in[i]==2 ) continue;
     29         return false;
     30     }
     31     return true;
     32 }
     33 
     34 bool check0(int a){//源点到a机器的input可不可以
     35     for(int i=1;i<=p;i++){
     36         if( machine[a].in[i]==1 ) return false;
     37     }
     38     return true;
     39 }
     40 
     41 bool check1(int a){//a机器的output到汇点可不可以
     42     for(int i=1;i<=p;i++){
     43         if( machine[a].out[i]!=1 ) return false;
     44     }
     45     return true;
     46 }
     47 
     48 int vis[1005];
     49 bool count_floor(){
     50     memset(layer,-1,sizeof(layer));
     51     layer[0]=0;
     52     queue<int> q;//int记录现在在的节点位置
     53     q.push(0);
     54     while(!q.empty()){
     55         int u = q.front(); q.pop();
     56         if(u==2*n+1) return true;
     57         for(int i=0;i<=2*n+1;i++){//枚举所有节点 
     58             if( G2[u][i]>0 && layer[i]==-1 ){
     59                 layer[i]=layer[u]+1;
     60                 q.push(i);
     61             }
     62         }
     63     } 
     64     return false;//搜不到汇点了 
     65 }
     66 
     67 int dinic(){
     68     //源点是0
     69     int maxflow=0;
     70     deque<int> s;//int记录目前dfs到的节点
     71     while( count_floor() ){
     72         s.push_back(0);
     73         memset(vis,0,sizeof(vis)); vis[0]=1;
     74         while(!s.empty()){
     75             int u = s.back();//先不急着pop_back掉
     76             if( u==2*n+1 ){//找到一条增广路径 
     77                 int minflow=INF,min_u;
     78                 for(int i=1;i<s.size();i++){
     79                     int u1=s[i-1],v1=s[i];
     80                     if( G2[u1][v1]<minflow ){ minflow=G2[u1][v1]; min_u=u1; }
     81                 }//找到一路上最细的管道
     82                 maxflow+=minflow;
     83                 for(int i=1;i<s.size();i++){
     84                     int u1=s[i-1],v1=s[i];
     85                     G2[u1][v1]-=minflow;//减掉原边
     86                     G2[v1][u1]+=minflow;//加上反向边 
     87                 }
     88                 while(!s.empty() && s.back()!=min_u) {
     89                     vis[ s.back() ] = 0;
     90                     s.pop_back();
     91                 }
     92             }//都结束了,自动回溯到最上面的点u使得u以上的树边flow不为0
     93             else{//到了一个点,向下dfs
     94                 int i;
     95                 for(i=0;i<=2*n+1;i++){
     96                     if( G2[u][i]>0 && layer[i]==layer[u]+1 && !vis[i] ){//每一次只往下一层走
     97                         vis[i]=1;
     98                         s.push_back(i);
     99                         break;
    100                     }    
    101                 }
    102                 if(i==2*n+2) s.pop_back(); 
    103             }     
    104         } 
    105     }
    106      
    107     return maxflow;
    108 }
    109 
    110 
    111 int main(){
    112     
    113     while(scanf("%d%d",&p,&n)!=EOF){
    114         for(int i=1;i<=n;i++){
    115             cin>>machine[i].flow;
    116             for(int j=1;j<=p;j++) cin>>machine[i].in[j];
    117             for(int j=1;j<=p;j++) cin>>machine[i].out[j];    
    118         }
    119     
    120         //开始建图
    121         for(int i=1;i<=n;i++) G2[i][i+n]=G[i][i+n]=machine[i].flow;//从n的input到n的output 
    122         //output代表的节点是机器的编号+n
    123         //源点是0,汇点是2n+1
    124         for(int i=1;i<=n;i++){
    125             if( check0(i) ) G2[0][i]=G[0][i]=INF;
    126             if( check1(i) ) G2[i+n][2*n+1]=G[i+n][2*n+1]=INF;
    127         } 
    128     
    129         //建每个机器的output能不能到其他机器的input
    130         for(int i=1;i<=n;i++){
    131             for(int j=1;j<=n;j++){
    132                 if(i==j) continue;
    133                 if( ok(i,j) ) G2[i+n][j]=G[i+n][j]=INF;
    134             }
    135         }
    136     
    137         cout<<dinic()<<" ";
    138         for(int i=1;i<=n;i++){
    139             for(int j=1;j<=n;j++){
    140                 if(i==j) continue;
    141                 if( ok(i,j) && G[i+n][j]-G2[i+n][j]>0 ) ans.push_back( node1(i,j,G[i+n][j]-G2[i+n][j]) );
    142             }
    143         } 
    144         cout<<ans.size()<<endl;
    145         for(int i=0;i<ans.size();i++) cout<<ans[i].from<<" "<<ans[i].to<<" "<<ans[i].vol<<endl;
    146         ans.clear();
    147     }
    148     
    149     return 0;    
    150 }
  • 相关阅读:
    NHibernate OR EES ,不能比较的比较
    Dubbo实现原理和实现机制
    xxljob学习1:整体架构
    xxljob学习2:用户端注册
    xxljob学习4:任务调度器
    xxljob学习3:服务端一次调度
    jQuery源码学习(1)——addClass
    jQuery 选择器项目实例
    javascript权威指南读书笔记(1)——对象
    easyui tabs源码阅读(未完待续)
  • 原文地址:https://www.cnblogs.com/ZhenghangHu/p/9410691.html
Copyright © 2020-2023  润新知