[BZOJ1834][ZJOI2010][最大流][最小費用最大流]網絡擴容

[題目]

給定一張有向圖,每條邊都有一個容量C和一個擴容費用W。這裏擴容費用是指將容量擴大1所需的費用。求: 1、 在不擴容的情況下,1到N的最大流; 2、 將1到N的最大流增加K所需的最小擴容費用。

[算法]

最大流,最小費用最大流

[分析]

最大流isap或dinic不必說,然後把每條邊重新加入圖中,有費用且容量爲INF,模擬擴容的過程。再新建一個超級源,與1連一條費用0,容量k的邊,跑最小費用最大流即可

[注意]

再跑最小費用最大流之前,原來的圖是不能刪的!要理解清楚每一步的含義……

[代碼]

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;

#define MAXN 2000
#define MAXM 30000
#define INF  1000000000

int totNode = 0;
int totEdge;
int point[MAXN], next[MAXM], v[MAXM], flow[MAXM], cap[MAXM], w[MAXM];
int dis[MAXN], lastedge[MAXN], deep[MAXN], num[MAXN], cur[MAXN];
int u[MAXM], vv[MAXM], cost[MAXM];
bool check[MAXN];
int n, m, k;

inline void addedge(int x, int y, int theCap, int theCost)
{
    totEdge++;
    next[totEdge] = point[x]; point[x] = totEdge; v[totEdge] = y;
    flow[totEdge] = 0; cap[totEdge] = theCap; w[totEdge] = theCost;
    totEdge++;
    next[totEdge] = point[y]; point[y] = totEdge; v[totEdge] = x;
    flow[totEdge] = 0; cap[totEdge] = 0; w[totEdge] =  -theCost;
}

inline void clear()
{
    totEdge = -1;
    memset(point, -1, sizeof(point));
    memset(next, -1, sizeof(next));
}

inline int addflow(int start, int end)
{
    int ans = INF;
    int now = end;
    while (now != start)
    {
        int temp = lastedge[now];
        ans = min(ans, cap[temp] - flow[temp]);
        now = v[temp^1];
    }   
    now = end;
    while (now != start)
    {
        int temp = lastedge[now];
        flow[temp] += ans;
        flow[temp^1] -= ans;
        now = v[temp^1];       
    }
    return ans;
}

inline void bfs(int start, int end)
{
    queue<int> q;
    while (!q.empty()) q.pop();
    memset(check, 0, sizeof(check));
    memset(deep, 0, sizeof(deep));
    q.push(end); deep[end] = 0; check[end] = true;
    while (!q.empty())
    {
        int now = q.front(); q.pop();
        for (int temp = point[now]; temp != -1; temp = next[temp])
        {
            int tt = temp ^ 1;
            if (!check[v[tt]] && flow[tt] < cap[tt])
            {
                deep[v[tt]] = deep[now] + 1;
                q.push(v[tt]);
                check[v[tt]] = true;
            }           
        }       
    }      
}

inline int isap(int start, int end)
{
    int ans = 0;
    int now = start;
    memset(num, 0, sizeof(num));
    bfs(start, end);
    for (int i = 1; i <= totNode; i++)
    {
        cur[i] = point[i];
        num[deep[i]]++;
    }
    while (deep[start] < totNode)
    {
        if (now == end)
        {
            ans += addflow(start, end);
            now = start;
        }
        bool isok = false;
        for (int temp = cur[now]; temp != -1; temp = next[temp])
            if (deep[now] == deep[v[temp]] + 1 && flow[temp] < cap[temp])
            {
                isok = true;
                lastedge[v[temp]] = temp;
                cur[now] = temp;
                now = v[temp];
                break;
            }
        if (!isok)
        {
            int minn = totNode - 1;
            for (int temp = point[now]; temp != -1; temp = next[temp])
                if (flow[temp] < cap[temp])
                    minn = min(minn, deep[v[temp]]);
            if (--num[deep[now]] == 0) break;
            num[deep[now] = minn + 1]++;
            cur[now] = point[now];
            if (now != start) now = v[lastedge[now]^1];
        }
    }
    return ans;
}   

inline bool spfa(int start, int end, int &maxflow, int &mincost)
{
    queue<int> q;
    while (!q.empty()) q.pop();
    memset(dis, 0x7f, sizeof(dis));
    memset(check, 0, sizeof(check));
    dis[start] = 0; q.push(start); check[start] = true;
    while (!q.empty())
    {
        int now = q.front(); q.pop();
        check[now] = false;
        for (int temp = point[now]; temp != -1; temp = next[temp])
            if (flow[temp] < cap[temp] && dis[now] + w[temp] < dis[v[temp]])
            {
                dis[v[temp]] = dis[now] + w[temp];
                lastedge[v[temp]] = temp;
                if (!check[v[temp]])
                {
                    check[v[temp]] = true;
                    q.push(v[temp]);
                }               
            }
    }
    if (dis[end] > INF) return false;
    int theAdd = addflow(start, end);
    maxflow += theAdd; mincost += theAdd * dis[end]; 
    return true;
}

int SolveMinCost(int start, int end)
{
    int mincost = 0, maxflow = 0;
    while (spfa(start, end, maxflow, mincost))
    {
        int debug = 1;
        debug = debug + 1;
    }
    return mincost;
}

int main()
{
    //freopen("input.txt","r",stdin);
    scanf("%d%d%d", &n, &m, &k);
    clear();
    for (int i = 1; i <= m; i++)
    {
        int tempCap;
        scanf("%d%d%d%d", &u[i], &vv[i], &tempCap, &cost[i]);
        addedge(u[i], vv[i], tempCap, 0);       
    }
    totNode = n;
    printf("%d ", isap(1, n));
    for (int i = 1; i <= m; i++)
        addedge(u[i], vv[i], INF, cost[i]);
    totNode++;
    addedge(totNode, 1, k, 0);
    printf("%d\n", SolveMinCost(totNode, n));
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章