首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

SGU 176 Flow construction 有源汇 有左右界的最小流

2013-11-01 
SGU 176Flow construction 有源汇 有上下界的最小流题意就是给出一个图。有源汇然后每条边都有容量的上下界

SGU 176 Flow construction 有源汇 有上下界的最小流


题意就是给出一个图。有源汇

然后每条边都有容量的上下界限制。

问的是是否有一个最小流,使得每条边得流量都满足流量限制,并且流量守恒

我使用的是二分的方法。

每次二分都要重新构图,然后计算。

构图的方法是按照论文中所说。

设原来的源汇为s, t, 附加源汇为S, T

对于一个点i,计算流入该点的下界总和减去流出该点的下界总和为M[i].

如果M[i]是正数,添加边(S,i),容量为M[i]

否则添加边(i, T) 容量为-M[i]

然后对于每条边,设上下届分为up和down, 起点终点为u,v

那么添加边(u, v)流量为up - down即可

由于我们要二分一个流量然后判断可行。

假设二分的流量是x,则添加边(t, s) 流量为x

然后求最大流看是否使得源s连出去的边都满流。若都满流即为可行流。

最后求得的最小的该x即为最终原图中的最小流

输出边时则输出边得流量加上原来的down。因为我们之前减掉了。


#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>#include <cstdlib>#include <cmath>#include <map>#include <sstream>#include <queue>#include <vector>#define MAXN 111#define MAXM 21111#define eps 1e-8#define INF 1000000009using namespace std;struct EDGE{    int v, next;    int w;} edge[MAXM];int head[MAXN], e;inline void init(){    memset(head, -1, sizeof(head));    e = 0;}inline void add(int u, int v, int w){    edge[e].v = v;    edge[e].w = w;    edge[e].next = head[u];    head[u] = e++;    edge[e].v = u;    edge[e].w = 0;    edge[e].next = head[v];    head[v] = e++;}int n;int h[MAXN];int gap[MAXN];int src, des;inline int dfs(int pos, int cost){    if (pos == des) return cost;    int j, minh = n - 1;    int lv = cost, d;    for (j = head[pos]; j != -1; j = edge[j].next)    {        int v = edge[j].v;        int w = edge[j].w;        if(w > 0)        {            if (h[v] + 1 == h[pos])            {                if (lv < edge[j].w) d = lv;                else d = edge[j].w;                d = dfs(v, d);                edge[j].w -= d;                edge[j ^ 1].w += d;                lv -= d;                if (h[src] >= n) return cost - lv;                if (lv == 0) break;            }            if (h[v] < minh) minh = h[v];        }    }    if (lv == cost)    {        --gap[h[pos]];        if (gap[h[pos]] == 0) h[src] = n;        h[pos] = minh + 1;        ++gap[h[pos]];    }    return cost - lv;}int sap(){    int ret = 0;    memset(gap, 0, sizeof(gap));    memset(h, 0, sizeof(h));    gap[0] = n;    while (h[src] < n) ret += dfs(src, INF);    return ret;}int nt, m;int xj[MAXN];int uu[MAXM], vv[MAXM], low[MAXM], z[MAXM];int id[MAXN][MAXN], eid, total, limit;void build(int x){    init();    for(int i = 0; i < m; i++)    {        id[uu[i]][vv[i]] = e;        add(uu[i], vv[i], z[i] - low[i]);    }    for(int i = 1; i <= nt; i++)    {        if(xj[i] > 0) add(src, i, xj[i]);        else add(i, des, -xj[i]);    }    add(nt, 1, x);}void gao(){    int l = 0, r = limit, mid;    while(l <= r)    {        mid = (l + r) >> 1;        build(mid);        if(sap() == total) r = mid - 1;        else l = mid + 1;    }    build(l);    sap();    printf("%d\n", l);    for(int i = 0; i < m; i++)    {        int tmp = id[uu[i]][vv[i]];        printf("%d ", edge[tmp ^ 1].w + low[i]);    }    printf("\n");}int main(){    while(scanf("%d%d", &nt, &m) != EOF)    {        init();        total = 0; limit = 0;        memset(xj, 0, sizeof(xj));        for(int i = 0; i < m; i++)        {            scanf("%d%d%d%d", &uu[i], &vv[i], &z[i], &low[i]);            if(low[i] == 1) low[i] = z[i];            xj[vv[i]] += low[i];            xj[uu[i]] -= low[i];            if(uu[i] == 1) limit += z[i];        }        src = nt + 1;        des = nt + 2;        n = des;        for(int i = 1; i <= nt; i++)            if(xj[i] > 0) total += xj[i];        build(INF);        if(sap() != total) printf("Impossible\n");        else gao();    }    return 0;}


热点排行