POJ 2112 2391 floyd 二分 最大流

这两道题很像,基本可以粘代码,解法相同,唯一不同之处在于建图。

2112题意:给出K+C个点,前K个点代表牛棚,之后的C个点代表牛,所有的牛都要转移到牛棚中去,然而每个牛棚最多能容纳M头牛,问最短多长时间可以将所有牛转移到牛棚中去(每条边不限制同一时间通过数量,牛可以同时移动)。输入数据第一行三个整数K C M,接下来一个邻接矩阵D,D[i][j]表示点i到点j的距离,D[i][i] = 0,当i!=j时D[i][j] == 0表示i与j之间没有直接的路径。

2391题意:给出F和P,表示有F个牛棚,P条连接牛棚之间的路径,之后F行,每行两个整数表示当前牛棚此时有多少牛和当前牛棚最多能容纳多少头牛。接下来P行每行三个整数(u,v,w)表示从牛棚u到牛棚v需要耗时w。边是无向的。初始态可能不满足每个牛棚中牛的数量都小于其容纳量,所以问要达到合法状态需要的最短时间。

除了建图之外,两道题做法是一样的。首先二分答案最短时间,之后建图,跑最大流,比较最大流和牛的总数量,继续二分。跑出的最大流表示的是最后有多少头牛在二分后限定的时间内移动后达到了合法状态。

那么先来看2112的建图,首先建立源点S和汇点T,S向每头牛连边,容量为1,每个牛棚向汇点连边,容量为M,关于二分的时间mid,枚举每头牛u和每个牛棚v,若u和v之间的最短路不大于mid,则u和v之间连边,容量不小于1即可(理论上应该是正无穷,因为这道题数据的特殊性,与S连边的点才可能会有这种类型的出边,而这些点与S之间的边容量为1)。

然后2391,这道题每个点既是牛也是牛棚的存在,所以建图不如上一道那么清晰明了。需要拆点,每个点i拆为i’和i”,S与每个i’连边,容量为i初始牛的数量,每个i”与T连边,容量为i牛碰容纳牛的数量。枚举每两个点,若u,v之间最短路不大于mid,u’和v”之间连边,容量正无穷。

然后解释一下为什么第二道题需要拆点。考虑这两道题网络流做法的意义,实际上这两道题的模型都是二分图,匹配边的入点是牛,出点是牛棚,流量表示这个入点有这么些牛最后移动到了出点代表的牛棚。如果第二题不拆点,直接建图就有可能不是二分图。

//poj 2112
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;

int K, C, M, maxd, D[250][250];

struct Edge {int u, v, flow, cap;};

struct Dinic
{
    int s, t, e, d[250], cur[250];
    vector <int> G[250];
    Edge E[80008];

    void addedge (int u, int v, int cap)
    {
        G[u].push_back(e), G[v].push_back(e+1);
        E[e].u = u, E[e].v = v, E[e++].cap = cap;
        E[e].u = v, E[e].v = u, E[e++].cap = 0;
    }

    void initialize ()
    {
        s = 0, t = K+C+1;
        for (int i = 1; i <= K; i++) addedge(i,t,M);
        for (int i = 1; i <= C; i++) addedge(s,i+K,1);
    }

    bool BFS ()
    {
        memset (d, -1, sizeof d);
        queue <int> q;
        q.push(s); d[s] = 0;
        while (!q.empty())
        {
            int u = q.front(); q.pop();
            for (int i = G[u].size()-1; i >= 0; i--)
            {
                Edge e0 = E[G[u][i]];
                if (d[e0.v] < 0 && e0.flow < e0.cap)
                    d[e0.v] = d[u]+1, q.push(e0.v);
            }
        }
        return d[t] >= 0;
    }

    int DFS (int u, int flow)
    {
        if (u == t || !flow) return flow;

        int f1 = 0, f2;
        for (int &i = cur[u]; i >= 0; i--)
        {
            Edge &e1 = E[G[u][i]];
            Edge &e2 = E[G[u][i]^1];
            if (d[e1.v] != d[u] + 1) continue;
            f2 = DFS(e1.v,min(flow,e1.cap-e1.flow));
            if (f2 > 0) 
                f1 += f2, e1.flow += f2,
                flow -= f2, e2.flow -= f2;
            if (!flow) break;
        }
        return f1;
    }

    int maxflow ()
    {
        int res = 0;
        while (BFS())
        {
            for (int i = s; i <= t; i++) cur[i] = G[i].size()-1;
            res += DFS(s,1<<30);
        }
        return res;
    }

    void replace (int T)
    {
        e = K+C<<1; // <1> e=K+C;
        for (int i = s; i <= t; i++) // <2> i <= T
        {
            int siz = G[i].size();
            while (siz && G[i][siz-1] >= e) G[i].resize(--siz);
        }
        for (int i = 1; i <= C; i++)
        for (int j = 1; j <= K; j++)
        if (D[i+K][j] <= T) addedge(i+K,j,1111);
        for (int i = 0; i < e; i++) E[i].flow = 0;
    }
}Solve;

void ReadinData ()
{
    scanf ("%d %d %d", &K, &C, &M);
    for (int i = 1; i <= K+C; i++)
    for (int j = 1; j <= K+C; j++)
    scanf ("%d", D[i]+j);
}

void Initialize ()
{
    for (int i = 1; i <= K+C; i++)
    for (int j = 1; j <= K+C; j++)
    if (i != j && !D[i][j]) D[i][j] = 1<<29; // <3> 1<<30
    for (int k = 1; k <= K+C; k++)
    for (int i = 1; i <= K+C; i++)
    for (int j = 1; j <= K+C; j++)
    if (i != j) D[i][j] = min (D[i][j], D[i][k]+D[k][j]);
    for (int i = 1; i <= K+C; i++)
    for (int j = 1; j <= K+C; j++) 
    if (D[i][j] != (1<<29)) maxd = max(maxd, D[i][j]);

    Solve.initialize();
}

void Soluation ()
{
    int l = 0, r = maxd, mid;
    while (l < r)
    {
        mid = l+r>>1;
        Solve.replace(mid);
        int mxf = Solve.maxflow();
        if (mxf == C) r = mid;
        else l = mid + 1;
    }
    printf ("%d\n", l);
}

int main ()
{
    ReadinData();
    Initialize();
    Soluation();
    return 0;
}
//poj 2391
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;

int n, m, sumcow, A[205], B[205];
long long sumtime, D[205][205];

struct Edge {int u, v, flow, cap;};

struct Dinic
{
    int s, t, e, cur[505], d[505];
    vector <int> G[505];
    Edge E[100005]; // E[40005]

    void addedge (int u, int v, int cap)
    {
        G[u].push_back(e), G[v].push_back(e+1);
        E[e].u = u, E[e].v = v, E[e++].cap = cap;
        E[e].u = v, E[e].v = u, E[e++].cap = 0;
    }

    bool BFS ()
    {
        queue <int> q;
        while (!q.empty()) q.pop();
        memset (d, -1, sizeof d);
        q.push(0); d[0] = 0;
        while (!q.empty())
        {
            int u = q.front(); q.pop();
            for (int i = G[u].size()-1; i >= 0; i--)
            {
                Edge e0 = E[G[u][i]];
                if (d[e0.v] < 0 && e0.cap > e0.flow) 
                    d[e0.v] = d[u]+1, q.push(e0.v);
            }
        }
        return d[t] > 0;
    }

    int DFS (int u, int flow)
    {
        if (u == t || !flow) return flow;
        int f1 = 0, f2;
        for (int &i = cur[u]; i >= 0; i--)
        {
            Edge &e1 = E[G[u][i]];
            Edge &e2 = E[G[u][i]^1];
            if (d[u]+1==d[e1.v] && (f2=DFS(e1.v,min(flow,e1.cap-e1.flow))) > 0)
            {
                f1 += f2, flow -= f2;
                e1.flow += f2, e2.flow -= f2;
                if (!flow) break;
            }
        }
        return f1;
    }

    int maxflow ()
    {
        int res = 0;
        while (BFS())
        {
            for (int i = s; i <= t; i++) cur[i] = G[i].size()-1;
            res += DFS(s,1<<30);
        }
        return res;
    }

    void replace (long long T) // long long
    {
        e = n*4;
        for (int i = s; i <= t; i++)
        {
            int siz = G[i].size();
            while (siz && G[i][siz-1] >= e) G[i].resize(--siz);
                                    //siz
        }
        for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
        if (D[i][j] <= T) addedge(i, j+n, 1<<30);
        for (int i = 0; i < e; i++) E[i].flow = 0; // whole
    }
}Solve;

void ReadinData ()
{
    scanf ("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) scanf ("%d %d", A+i, B+i);
    memset(D, 0x3f, sizeof D);
    for (int i = 1; i <= n; i++) D[i][i] = 0, sumcow += A[i];
    for (int i = 1; i <= m; i++) 
    {
        int a, b; long long c; 
        scanf ("%d %d %lld", &a, &b, &c);
        D[a][b] = D[b][a] = min(D[a][b],c);
        sumtime += c;
    }
}

void Initialize ()
{
    for (int k = 1; k <= n; k++)
    for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++) // j = i
    if (i!=j) D[i][j] = min(D[i][j], D[i][k]+D[k][j]);
    Solve.s = 0, Solve.t = n*2+1;
    for (int i = 1; i <= n; i++)
        Solve.addedge(0,i,A[i]), Solve.addedge(i+n,n*2+1,B[i]);
}

void Soluation ()
{
    long long l = 0, r = sumtime+1, mid;
    while (l < r)
    {
        mid = l+r>>(long long)1;
        Solve.replace(mid);
        int res = Solve.maxflow();
        if (res == sumcow) r = mid;
        else l = mid + 1;
    }
    if (l <= sumtime) printf ("%lld\n", l);
    else puts("-1");
}

int main ()
{
    ReadinData();
    Initialize();
    Soluation();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值