Drainage Ditches HDU

来源:互联网 发布:黑马程序员训练营 编辑:程序博客网 时间:2024/06/07 12:01

Every time it rains on Farmer John’s fields, a pond forms over Bessie’s favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie’s clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch.
Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.
Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.
Input
The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.
Output
For each case, output a single integer, the maximum rate at which water may emptied from the pond.
Sample Input
5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
Sample Output
50

关于网络流的理论实现可以参考http://blog.csdn.net/y990041769/article/details/21026445(里面的代码看不懂)一直在思考怎么实现,最后还是写出来了,纯手打的网络流。。。作死。
算法实现的几个细节:
1.当找到一条增广路的时候,那么在这条路上的所有边需要减去这些边里流量最小的一个,就是说需要有对边的权值行修改,与此同时反向边需要相应增加等值的容量
2.怎样从一条边快速确定他的反向边
3.while循环里嵌套了一个bfs

#include<cstdio>#include<iostream>#include<queue>#include<vector> #include<cstring>using namespace std;struct node{    int from,to,c;}edge[405];//把边保存在数组里struct se{    int point;    int minC;    int index;    int  lastIndex;}que[400];//bfs需要数据结构int k;vector<int> graph[205];//那建图保存的是边数组的indexint head,endd;void addEdge(int x,int y,int c){    edge[k].from=x;    edge[k].to=y;    edge[k].c=c;    graph[x].push_back(k);    k++;}void init(int n){    for(int i=1;i<=n;i++)        graph[i].clear();    k=0;}int n,m;bool vis[205];int work(){    bool sign;    int ans=0;    for(;;)    {        sign=false;        memset(vis,false,sizeof(vis));        se b,tail;        b.point=1,b.minC=100000000;        b.lastIndex=-1;        head=endd=0;        que[endd++]=b;        while(head<endd)//数组实现队列,想用queue但是需要搞指针,怎么搞都有bug,只能用数组实现队列了        {            se now=que[head++];            //printf("%d\n",now.point);            int p=now.point;            for(int i=0;i<graph[p].size();i++)            {                int v=edge[graph[p][i]].to;                int cc=edge[graph[p][i]].c;                //printf("%d\n",v);                if(vis[v]||cc==0)//容量为0相当于边不存在                    continue;                if(v==m)                {                    tail.index=graph[p][i];                    tail.minC=min(cc,now.minC);//因为需要找到最小的可曾容量                    tail.lastIndex=head-1;                    tail.point=m;                    sign=true;                    break;                }                else                {                    //cout<<"haha"<<endl;                    vis[v]=true;                    se temp;                    temp.index=graph[p][i];                    temp.minC=min(cc,now.minC);                    //cout<<"haha2"<<endl;                    temp.lastIndex=head-1;                    //cout<<"haha3"<<endl;                     temp.point=v;                    que[endd++]=temp;                }            }        }        if(sign)//说明找到了        {            int h=tail.minC;//这个点是最小可增加容量            ans+=h;            while(tail.lastIndex!=-1)//从这个汇点开始,一直修改边的权值,如果用queue就得搞指针,就是在这里怎么搞都有问题,所以用数组下标代替指针了            {                //cout<<q->point<<endl;                edge[tail.index].c-=h;                if(tail.index&1)//找到相应的反向边,这是加边的特性决定的                    edge[tail.index-1].c+=h;                else                    edge[tail.index+1].c+=h;                tail=que[tail.lastIndex];                           }            //printf("haha\n");        }        else            break;    }    return ans;}int main(){    int x,y,c;    while(scanf("%d%d",&n,&m)==2)    {        init(m);        while(n--)        {            scanf("%d%d%d",&x,&y,&c);            addEdge(x,y,c);            addEdge(y,x,0);//所以0,1是一对反向边,2,3是反向边,就是说2*n和2*n+1是一对反向边        }        printf("%d\n",work());    }    return 0;}