Drainage Ditches HDU - 1532 (网络流之最大流)(EdmondsKarp算法)

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];//那建图保存的是边数组的index
int 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值