zoukankan      html  css  js  c++  java
  • 最大流、最小割算法

    #include<bits/stdc++.h>
    using namespace std;
    //最小割就是把起点及其他分成一个城市,终点及其他分成一个城市,当两个城市之间的线路的流量都满载时,的分法。
    //当最大流算法结束时,flag数组不是0的都是从s可达的,而且不可达的原因是没有残余了,所以就找到了最小割
    
    const int maxn=1001;
    int G[maxn][maxn],pre[maxn],n,m,flow[maxn][maxn],a[maxn];//flow是当前的流量 a 代表到某个点的最小残余流量
    //通过前驱数组求一条路径,当然结果可能会多了不是这条路径上的点的前驱,因为不一定能一次到
    int flg[maxn];
    int maxflow(int s,int t){
        int f=0;
        //使用bfs,因为每次都要找一条路径,bfs快
        memset(flow,0,sizeof(flow));
    while(1){
        queue<int> q;
        q.push(s);
        memset(flg,0,sizeof(flg));
        memset(pre,0,sizeof(pre));
        memset(a,0x3f3f3f3f,sizeof(a));
        flg[s]=1;//必须设置
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(int i=1;i<=n;i++){
                //有流量剩余
                //因为有残量才能遍历,所以t可能遍历不到
                if(!flg[i]&&G[x][i]!=0&&G[x][i]>flow[x][i]){
                    pre[i]=x;
                    flg[i]=1;
                    //到i的最小=到x的最小 和 x到i的 小的那个
                    a[i]=min(a[x],G[x][i]-flow[x][i]);//不用整体的min,因为那条路径不一定在s->t上
                    //注意,他没有对a[i]再取最小值,这样就可以保证pre和a[t]是对应的同一条边
                    //当然也可以,这个就是取所有可达边的最小值残余的 最小值
                    // if(a[i]>min(a[x],G[x][i]-flow[x][i])){
                    //     a[i]=min(a[x],G[x][i]-flow[x][i]);
                    //     pre[i]=x;
                    // }
    
                    // if(i==t) break; //两层循环无法退出
                    q.push(i);
                }
            }
            if(x==t) break;//我觉得可以提前终止,如果遍历到了t
        }
        cout<<a[t]<<endl;
        //其实当残量为0时,根本遍历不到
        if(a[t]==0x3f3f3f3f){
            //输出最小割
            cout<<"minimum ge
    ";
            cout<<"Set S
    ";
            for(int i=1;i<=n;i++) if(flg[i]) cout<<i<<" ";cout<<endl;
            cout<<"Set T
    ";
            for(int i=1;i<=n;i++) if(!flg[i]) cout<<i<<" ";cout<<endl;
        }
        if(a[t]==0x3f3f3f3f) return f;//没路径退出
    
        //有残余,对于pre找到的路径上的每个点,都更新flow
        for(int i=t;i!=s;i=pre[i]){
            //注意到s停,因为用到pre
            flow[pre[i]][i]+=a[t];
            flow[i][pre[i]]-=a[t];//别忘了减,根据流量的定义,对于a-> b->a的边有用
        }
        f+=a[t];
    }
    }
    int main() {
        cin>>n>>m;
        memset(G,0,sizeof(G));
        for(int i=0;i<m;i++){
            int x,y,z;
            cin>>x>>y>>z;
            G[x][y]=z;
        }
        cout<<maxflow(5,6)<<endl;
        return 0;
    }
  • 相关阅读:
    Java多线程之Exchanger
    Java8 比AtomicLong更加高效的原子操作LogAdder
    synchronized父子类对象锁重入
    java8 stream多字段排序
    利用java代码给mongo数据库加索引、删除索引等操作
    C++之IO
    C++之类的定义和性质
    C++之动态内存与类型转换
    C++之字符与其他数据类型
    C++之函数与模板
  • 原文地址:https://www.cnblogs.com/MorrowWind/p/13056645.html
Copyright © 2011-2022 走看看