1. 程式人生 > >【最大流 模板 Dinic】POJ 1459 Power Network

【最大流 模板 Dinic】POJ 1459 Power Network

Problem Description

給你n, np, nc, m。分別代表有n個點,其中np個是發電站,nc個是消費者,剩下n-np-nc個就是中轉站。接下來給你m條邊,每條邊格式(u,v)w。代表u點到v點這條線路最大能夠運輸w的電。最後給你np個點最大能夠輸出的電,nc個點最大能夠接收的電(格式:(u)w, u這個點能夠輸出(接收)最大的電,發電站的點是輸出,消費者的點是接收)。

思路:

所有發電站看成一個超級源點s,所有消費者看成一個超級匯點t。如何實現,從s向每個源點連一條容量為對應最大流出容量的邊,從每個匯點向t連一條容量為對應最大流入容量的邊。然後求s->t的最大流即可。

給了兩種形式的Dinic。存圖都用了鄰接矩陣,這樣可以好觀察出兩種Dinic的那些細節不一樣 時間複雜度O(|E||V|^2)

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int mm = 200;
const int inf = 0x3f3f3f3f;
int Map[mm][mm], n;//存圖
int dis[mm];//記錄mm到超級源點的最短距離
void bfs(int s, int t)//求dis[]陣列
{ memset(dis, -1, sizeof(dis)); dis[s] = 0; queue<int> q; q.push(s); while(!q.empty()) { s = q.front(); q.pop(); for(int i = 1; i <= t; i++) { if(dis[i] == -1 && Map[s][i])//容量不為0 { dis[i] = dis[s] + 1
; q.push(i); } } } } int dfs(int s, int t, int f)//s為當前點,t為超級匯點,f為當前流入s點的流量 { if(s == t) return f;//代表到達超級匯點,直接返回當前流到匯點的流量 int ans = 0;//用來記錄當前點,輸出的最大流量 for(int i = 1; i <= t; i++) { if(Map[s][i] && dis[i] > dis[s]) { int d = dfs(i, t, min(f, Map[s][i])); if(d > 0)//代表到達了匯點,到達匯點的這條增廣路,最小的流量(限制流量) { Map[s][i] -= d;//正向邊-d Map[i][s] += d;//反向邊+d ans += d;//更新當前點的,輸出的最大流量 f -= d;//到達當前點的流量-d if(!f) break;//如果當前點已經沒有可以輸出的流量,退出迴圈 } } } if(ans) return ans;//當前點,輸出的最大流量有的話 dis[s] = -1;//沒有就標記-1,再到這點也沒意義了。 return 0; } int Dinic(int s, int t) { int Max_flow = 0, flow; for(;;){ bfs(s, t);//先跑bfs if(dis[t] < 0) break;//代表到達不了t,直接退出迴圈 Max_flow += dfs(s, t, inf);//更新最大流 } return Max_flow; } int main() { int np, nc, m, u, v, w, i; char s[20]; while(~scanf("%d %d %d %d", &n, &np, &nc, &m)) { memset(Map, 0, sizeof(Map));//初始化 while(m--)//建圖 { scanf("%s", s); sscanf(s, "%*c%d%*c%d%*c%d", &u, &v, &w); Map[u + 1][v + 1] = w; } for(i = 0; i < np; i++) { scanf("%s", s); sscanf(s, "%*c%d%*c%d", &u, &w); Map[0][u + 1] = w; } n = n + 1; for(i = 0; i < nc; i++) { scanf("%s", s); sscanf(s, "%*c%d%*c%d", &u, &w); Map[u + 1][n] = w; } //0為超級源點,n為超級匯點 printf("%d\n", Dinic(0, n)); } return 0; }

第二種型別主要就標識一下,那些地方不一樣。就不那麼詳細的註釋了

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int mm = 200;
const int inf = 0x3f3f3f3f;
int Map[mm][mm], n;
int dis[mm], iter[mm];//多了個iter[]陣列,作用當前弧,在其之前的邊已經沒有用了。
void bfs(int s, int t)
{
    memset(dis, -1, sizeof(dis));
    dis[s] = 0;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        s = q.front(); q.pop();
        for(int i = 1; i <= t; i++)
        {
            if(dis[i] == -1 && Map[s][i])
            {
                dis[i] = dis[s] + 1;
                q.push(i);
            }
        }
    }
}
int dfs(int s, int t, int f)
{
    if(s == t) return f;
    for(int &i = iter[s]; i <= t; i++)//i是取iter[s]地址
    //下一次dfs的時候就可以直接跳過之前s為起點,訪問過的邊,這就是iter[]的作用,避免浪費的搜尋
    {
        if(i == 0) continue;//從1點開始搜尋
        if(Map[s][i] && dis[i] > dis[s])
        {
            //這裡是直接找到增光路,然後一路返回到超級源點,然後退出迴圈,這時候你就能理解呼叫的時候為什麼是迴圈,iter[]陣列為何要這樣了。
            int d = dfs(i, t, min(f, Map[s][i]));
            if(d > 0)
            {
                Map[s][i] -= d;
                Map[i][s] += d;
                return d;
            }
        }
    }
    return 0;
}
int Dinic(int s, int t)
{
    int Max_flow = 0, flow;
    for(;;){
        bfs(s, t);
        if(dis[t] < 0) break;
        memset(iter, 0, sizeof(iter));//初始化為0,但是是從1點開始搜,所以一會兒加個continue就可以了
        while((flow = dfs(s, t, inf)) > 0)//不一樣的點。這裡是迴圈,一會兒解釋為什麼
        {
            Max_flow += flow;
        }
    }
    return Max_flow;
}
int main()
{
    int np, nc, m, u, v, w, i;
    char s[20];
    while(~scanf("%d %d %d %d", &n, &np, &nc, &m))
    {
        memset(Map, 0, sizeof(Map));
        while(m--)
        {
            scanf("%s", s);
            sscanf(s, "%*c%d%*c%d%*c%d", &u, &v, &w);
            Map[u + 1][v + 1] = w;
        }
        for(i = 0; i < np; i++)
        {
            scanf("%s", s);
            sscanf(s, "%*c%d%*c%d", &u, &w);
            Map[0][u + 1] = w;
        }
        n = n + 1;
        for(i = 0; i < nc; i++)
        {
            scanf("%s", s);
            sscanf(s, "%*c%d%*c%d", &u, &w);
            Map[u + 1][n] = w;
        }
        printf("%d\n", Dinic(0, n));
    }
    return 0;
}