ACM/ICPC 之 有流量上下界的网络流-Dinic(可做模板)(POJ2396)

 

 

//有流量上下界的网络流
//Time:47Ms     Memory:1788K
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;

#define MAXC 25
#define MAXN 250
#define MAXE 100000
#define INF 0x3f3f3f3f

struct Edge{
    int u,v,f,next;
    Edge(){}
    Edge(int uu, int vv, int ff, int nn):u(uu), v(vv), f(ff), next(nn){}
}e[MAXE];

int n, m;
int S,T,s,t;
int sn[MAXN], sm[MAXC]; //行和,列和
int up[MAXN][MAXC], down[MAXN][MAXC];      //上界与下界
int in[MAXN], out[MAXN];    //出入度
int h[MAXN], le;
int d[MAXN];
int ans[MAXN][MAXC];

void add(int u,int v,int f)
{
    e[le] = Edge(u, v, f, h[u]);    h[u] = le++;
    e[le] = Edge(v, u, 0, h[v]);    h[v] = le++;
}

bool Init()
{
    int TT;
    bool result = true;
    scanf("%d", &TT);
    while(TT--){
        int x, y, v;
        int x1,x2,y1,y2;
        char op[2];
        scanf("%d%d%s%d", &x, &y, op, &v);
        if(!result) continue;
        x1 = x2 = x;    y1 = y2 = y;
        if(x == 0){ x1 = 1; x2 = n;}
        if(y == 0){ y1 = 1; y2 = m;}
        for(int i = x1; i <= x2; i++)
        {
            for(int j = y1; j <= y2; j++)
            {
                if(op[0] == '='){
                    if(v > up[i][j] || v < down[i][j]) result = false;
                    up[i][j] = down[i][j] = v;
                }
                else if(op[0] == '>')
                    down[i][j] = max(down[i][j], v+1);
                else up[i][j] = min(up[i][j], v-1);
                if(up[i][j] < down[i][j]) result = false;
            }
        }
    }
    return result;
}

void Build()    //建图
{
    memset(h, -1, sizeof(h));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    le = 0;
    s = 0;  t = n+m+1;  //原图源汇点
    S = t+1;  T = t+2;  //超级源汇点
    for(int i =1; i <= n; i++)  //建立初始各边
    {
        for(int j = 1; j <= m; j++)
        {
            int x = i, y = j + n;
            add(x, y, up[i][j] - down[i][j]);
            in[y] += down[i][j];    out[x] += down[i][j];
        }
    }
    for(int i = 1; i <= n; i++)   //从s流出的流量
    {
        in[i] += sn[i];   out[s] += sn[i];
    }
    for(int i = 1; i <= m; i++) //到t的流量
    {
        in[t] += sm[i]; out[i+n] += sm[i];
    }
    for(int i = 0; i <= n+m+1; i++) //新建补边
    {
        int x,y,w;
        if(in[i] > out[i])  {
            out[S] += in[i] - out[i];
            add(S,i,in[i] - out[i]);
        }
        else if(in[i] < out[i]) add(i, T, out[i] - in[i]);
    }
    add(t, s, INF);
}

bool BFS()
{
    memset(d, -1, sizeof(d));
    queue<int> q;
    q.push(S);  d[S] = 0;
    while(!q.empty()){
        int cur = q.front();
        q.pop();
        for(int i = h[cur]; i != -1; i = e[i].next)
        {
            int v = e[i].v;
            if(d[v] == -1 && e[i].f)
            {
                d[v] = d[cur] + 1;
                if(v == T) return true;
                q.push(v);
            }
        }
    }
    return false;
}

int DFS(int x, int sum)
{
    if (x == T || sum == 0) return sum;
	int src = sum;
	for (int i = h[x]; i != -1; i = e[i].next)
	{
	    int v = e[i].v;
		if (d[v] == d[x] + 1 && e[i].f)
		{
			int tmp = DFS(v, min(sum, e[i].f));
			e[i].f -= tmp;
			e[i^1].f += tmp;
			sum -= tmp;
		}
	}
	return src - sum;
}

int Dinic()
{
    int maxflow = 0;
    while(BFS()){
        maxflow += DFS(S, INF);
    }
    return maxflow;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int TT;
    scanf("%d",&TT);
    while(TT--){
        memset(e, 0, sizeof(e));
        memset(up, INF, sizeof(up));
        memset(down, 0 ,sizeof(down));
        scanf("%d%d", &n,&m);
        for(int i = 1; i <= n; i++)
            scanf("%d", &sn[i]);
        for(int i = 1; i <= m; i++)
            scanf("%d", &sm[i]);
        if(!Init()){   //预处理得到矛盾
            printf("IMPOSSIBLE\n\n");
            continue;
        }
        Build();    //构图
        if(Dinic() != out[S])   printf("IMPOSSIBLE\n\n");
        else{
            for(int i = 1; i <= n; i++)
                for(int j = h[i]; j != -1; j = e[j].next)
                    ans[i][e[j].v-n] = e[j^1].f + down[i][e[j].v-n];
            for(int i = 1; i <= n; i++)
            {
                for(int j = 1; j < m; j++)
                    printf("%d ", ans[i][j]);
                printf("%d\n", ans[i][m]);
            }
            printf("\n");
        }
    }
    return 0;
}

 

    原文作者:Inkblots
    原文地址: https://www.cnblogs.com/Inkblots/p/5740650.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注