POJ 1459-Power Network(最大流-Edmond-Karp演算法)

kewlgrl發表於2017-02-13
Power Network
Time Limit: 2000MS   Memory Limit: 32768K
Total Submissions: 27758   Accepted: 14435

Description

A power network consists of nodes (power stations, consumers and dispatchers) connected by power transport lines. A node u may be supplied with an amount s(u) >= 0 of power, may produce an amount 0 <= p(u) <= pmax(u) of power, may consume an amount 0 <= c(u) <= min(s(u),cmax(u)) of power, and may deliver an amount d(u)=s(u)+p(u)-c(u) of power. The following restrictions apply: c(u)=0 for any power station, p(u)=0 for any consumer, and p(u)=c(u)=0 for any dispatcher. There is at most one power transport line (u,v) from a node u to a node v in the net; it transports an amount 0 <= l(u,v) <= lmax(u,v) of power delivered by u to v. Let Con=Σuc(u) be the power consumed in the net. The problem is to compute the maximum value of Con. 

An example is in figure 1. The label x/y of power station u shows that p(u)=x and pmax(u)=y. The label x/y of consumer u shows that c(u)=x and cmax(u)=y. The label x/y of power transport line (u,v) shows that l(u,v)=x and lmax(u,v)=y. The power consumed is Con=6. Notice that there are other possible states of the network but the value of Con cannot exceed 6. 

Input

There are several data sets in the input. Each data set encodes a power network. It starts with four integers: 0 <= n <= 100 (nodes), 0 <= np <= n (power stations), 0 <= nc <= n (consumers), and 0 <= m <= n^2 (power transport lines). Follow m data triplets (u,v)z, where u and v are node identifiers (starting from 0) and 0 <= z <= 1000 is the value of lmax(u,v). Follow np doublets (u)z, where u is the identifier of a power station and 0 <= z <= 10000 is the value of pmax(u). The data set ends with nc doublets (u)z, where u is the identifier of a consumer and 0 <= z <= 10000 is the value of cmax(u). All input numbers are integers. Except the (u,v)z triplets and the (u)z doublets, which do not contain white spaces, white spaces can occur freely in input. Input data terminate with an end of file and are correct.

Output

For each data set from the input, the program prints on the standard output the maximum amount of power that can be consumed in the corresponding network. Each result has an integral value and is printed from the beginning of a separate line.

Sample Input

2 1 1 2 (0,1)20 (1,0)10 (0)15 (1)20
7 2 3 13 (0,0)1 (0,1)2 (0,2)5 (1,0)1 (1,2)8 (2,3)1 (2,4)7
         (3,5)2 (3,6)5 (4,2)7 (4,3)5 (4,5)1 (6,0)5
         (0)5 (1)2 (3)2 (4)1 (5)4

Sample Output

15
6

Hint

The sample input contains two data sets. The first data set encodes a network with 2 nodes, power station 0 with pmax(0)=15 and consumer 1 with cmax(1)=20, and 2 power transport lines with lmax(0,1)=20 and lmax(1,0)=10. The maximum value of Con is 15. The second data set encodes the network from figure 1.

Source


題目意思:

網路有N個點,可能是發電站,消耗站或排程器。
其中有NP個發電站提供電,NC個消耗站消耗電排程站不提供也不消耗電,M條單向線路。
先給出M條單向線路的(U,V)Z,表示站U到站V傳輸的最大功率是Z;
再給出NP個發電站的(U)Z,表示發電站U提供的最大功率是Z;
最後給出NC個消耗站的(U)Z,表示消耗U消耗的最大功率是Z。
求這個網路能夠消耗的最大功率。

解題思路:

增加一個超級源點0,用於將發電站提供的電錶示為發電站從超級源點得到電,即超級源點到發電站傳輸的最大功率是發電站U提供的最大功率;
增加一個超級匯點N+1,用於將消耗消耗的電錶示為消耗站向超級匯點輸出電,即消耗超級匯點傳輸的最大功率是消耗U消耗的最大功率。
然後使用Edmond-Karp演算法,求出超級源點到超級匯點的最大流。

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define INF 0xfffffff
#define MAXN 201
int maxData = 0x7fffffff;
int capacity[MAXN][MAXN]; //記錄殘留網路的容量
int flow[MAXN];           //標記從源點到當前節點實際還剩多少流量可用
int pre[MAXN];            //標記在這條路徑上當前節點的前驅,同時標記該節點是否在佇列中
int n,np,nc,m;            //總結點數、發電站、消耗器和線路數
queue<int> myqueue;
int BFS(int src,int des)
{
    int i;
    while(!myqueue.empty())       //佇列清空
        myqueue.pop();
    for(i=0; i<=n+1; ++i)
    {
        pre[i]=-1;
    }
    pre[src]=0;
    flow[src]= maxData;
    myqueue.push(src);
    while(!myqueue.empty())
    {
        int index = myqueue.front();
        myqueue.pop();
        if(index == des)            //找到了增廣路徑
            break;
        for(i=0; i<=n+1; ++i)
        {
            if(i!=src && capacity[index][i]>0 && pre[i]==-1)
            {
                pre[i] = index; //記錄前驅
                flow[i] = min(capacity[index][i],flow[index]);   //關鍵:迭代的找到增量
                myqueue.push(i);
            }
        }
    }
    if(pre[des]==-1)      //殘留圖中不再存在增廣路徑
        return -1;
    else
        return flow[des];
}
int maxFlow(int src,int des)
{
    int increasement= 0;
    int sumflow = 0;
    while((increasement=BFS(src,des))!=-1)
    {
        int k = des;          //利用前驅尋找路徑
        while(k!=src)
        {
            int last = pre[k];
            capacity[last][k] -= increasement; //改變正向邊的容量
            capacity[k][last] += increasement; //改變反向邊的容量
            k = last;
        }
        sumflow += increasement;
    }
    return sumflow;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("F:/cb/read.txt","r",stdin);
    //freopen("F:/cb/out.txt","w",stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    int i;
    int start,end,ci;
    while(cin>>n>>np>>nc>>m)
    {
        char c;
        memset(capacity,0,sizeof(capacity));
        memset(flow,0,sizeof(flow));
        for(i=0; i<m; ++i)
        {
            cin>>c>>start>>c>>end>>c>>ci;
            ++start,++end;
            capacity[start][end]+=ci;//此處注意可能出現多條同一起點終點的情況
        }
        for(i=0; i<np; ++i) //超級源點0
        {
            cin>>c>>end>>c>>ci;
            ++end;
            capacity[0][end]+=ci;
        }
        for(i=0; i<nc; ++i) //超級匯點n+1
        {
            cin>>c>>start>>c>>ci;
            ++start;
            capacity[start][n+1]+=ci;
        }
        cout<<maxFlow(0,n+1)<<endl;
    }
    return 0;
}
/*
2 1 1 2 (0,1)20 (1,0)10 (0)15 (1)20
7 2 3 13 (0,0)1 (0,1)2 (0,2)5 (1,0)1 (1,2)8 (2,3)1 (2,4)7
         (3,5)2 (3,6)5 (4,2)7 (4,3)5 (4,5)1 (6,0)5
         (0)5 (1)2 (3)2 (4)1 (5)4
*/


相關文章