poj1273---Drainage Ditches

tips:

  1.增光路---层叠相消---相当于改变

  2.找到一条可行路,反向建边,改变原来的容量,形成残余网络

  3.每条流的流量来源重新分配---也就是所说的可以反悔

  4.三个性质证明反向边---中间结点流入==流出

  5.G[u][v]=0---表示无边

  4.ref:gw_netglow.pdf和紫书

//需要先补下图的bfs遍历
//poj1273
/*input
5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
*/
/*output
50
*/
//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
using namespace std;
int Prev[300];//路径上每个节点的前驱结点,联想并查集里
int G[300][300];
bool Visited[300];
int n,m;
unsigned Augment(){
    int v;
    int i;
    deque<int> q;//双向队列
    memset(Prev,0,sizeof(Prev));
    memset(Visited,0,sizeof(Visited));
    Prev[1]=0;
    Visited[1]=1;
    q.push_back(1);
    bool bFindPath=false;
    //用bfs寻找一条源到汇的可行路径
    while(!q.empty()){
        v=q.front();q.pop_front();
        for(int i=1;i<=m;i++){//m是顶点
            if(G[v][i]>0 && Visited[i] == 0){
                Prev[i]=v;
                Visited[i]=1;
                if(i == m){
                    bFindPath=true;
                    q.clear();
                    break;//跳出while循环
                }
                else
                    q.push_back(i);
            }
        }

    }
    if(!bFindPath) return 0;
    int nMinFlow=0x3fffffff;
    v=m;
    //寻找路径上容量最小的边,其容量就是此次增加的流量
    while(Prev[v]){
        nMinFlow=min(nMinFlow,G[Prev[v]][v]);
        v=Prev[v];
    }
    v=m;
    //沿此路径添加反向边,同时修改路径上的每条边的容量
    while(Prev[v]){
        G[Prev[v]][v]-=nMinFlow;
        G[v][Prev[v]]+=nMinFlow;
        v=Prev[v];
    }
    return nMinFlow;
}
int main(){
    while(cin>>n>>m){//n条边,m个顶点

        int s,e,c;
        memset(G,0,sizeof(G));//邻接矩阵存图
        for(int i=0;i<n;i++){
            cin>>s>>e>>c;
            G[s][e]+=c;//两点间可能有多条边
        }
        unsigned int Maxflow=0;
        unsigned int aug;
        while(aug=Augment())//还能找到增广路---直到不能找到增广路
            Maxflow+=aug;
        cout<<Maxflow<<endl;
    }
    return 0;
}
View Code

 //被poj1455难住了o(╥﹏╥)o,神搜吖

posted @ 2018-08-10 22:51  SUMay  阅读(112)  评论(0编辑  收藏  举报