POJ2396 Budget 【带下界的最大流】

Budget

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 5962   Accepted: 2266   Special Judge

Description

We are supposed to make a budget proposal for this multi-site competition. The budget proposal is a matrix where the rows represent different kinds of expenses and the columns represent different sites. We had a meeting about this, some time ago where we discussed
the sums over different kinds of expenses and sums over different sites. There was also some talk about special constraints: someone mentioned that Computer Center would need at least 2000K Rials for food and someone from Sharif Authorities argued they wouldn‘t
use more than 30000K Rials for T-shirts. Anyway, we are sure there was more; we will go and try to find some notes from that meeting.

And, by the way, no one really reads budget proposals anyway, so we‘ll just have to make sure that it sums up properly and meets all constraints.

Input

The first line of the input contains an integer N, giving the number of test cases. The next line is empty, then, test cases follow: The first line of each test case contains two integers, m and n, giving the number of rows and columns (m <= 200, n <= 20).
The second line contains m integers, giving the row sums of the matrix. The third line contains n integers, giving the column sums of the matrix. The fourth line contains an integer c (c < 1000) giving the number of constraints. The next c lines contain the
constraints. There is an empty line after each test case.

Each constraint consists of two integers r and q, specifying some entry (or entries) in the matrix (the upper left corner is 1 1 and 0 is interpreted as "ALL", i.e. 4 0 means all entries on the fourth row and 0 0 means the entire matrix), one element from the
set {<, =, >} and one integer v, with the obvious interpretation. For instance, the constraint 1 2 > 5 means that the cell in the 1st row and 2nd column must have an entry strictly greater than 5, and the constraint 4 0 = 3 means that all elements in the fourth
row should be equal to 3.

Output

For each case output a matrix of non-negative integers meeting the above constraints or the string "IMPOSSIBLE" if no legal solution exists. Put one empty line between matrices.

Sample Input

2

2 3
8 10
5 6 7
4
0 2 > 2
2 1 = 3
2 3 > 2
2 3 < 5 

2 2
4 5
6 7
1
1 1 > 10

Sample Output

2 3 3
3 3 4 

IMPOSSIBLE

Source

Tehran 2003 Preliminary

这题做得真是抓狂啊,前前后后断断续续用了三天时间,主要时间都卡在一个手误上,敲错了一个字母...

题意:有一个n*m 的方阵, 方阵里面的数字未知, 但是我们知道如下约束条件:

1>  每一行的数字的和

2>  每一列的数字的和

3>  某些格子里的数,大小有限制。比如规定第2行第3 列的数字必须大于5( 或必须小于3, 或必须等于10等)

求解是否存在在满足所有的约束的条件下用正数来填充该方阵的方案, 若有, 输出填充后的方阵, 否则输出IMPOSSIBLE.

题解:这道题可以转化成容量有上下界的最大流问题, 将方阵的行从1……n 编号, 列n+1……n+m 编号, 添加源点s=0 和汇点t=n+m+1.

1> 将源点和每一个行节点相连, 相连所形成的边的容量和下界置为该行所有数字的和

2> 将每一个列节点和汇点相连, 相连所形成的边的容量和下界都置为该列所有数字的和

3> 从每个行节点到每个列节点连边,容量为无穷大

4>  如果u 行v 列的数字必须大于w, 则边<u,v+n> 流量的下界是w+1

5>  如果u 行v 列的数字必须小于w, 则边<u,v+n> 容量改为w-1

6>  如果u 行v 列的数字必须等于w, 则边<u,v+n> 流量的下界和容量都是w

找到的可行流(也是最大流),就是问题的解

本题trick:

1) W 可能为负数,产生流量下界为负数的情况。应处理成0

2) 数据本身可能矛盾。比如前面说了 (2,1) =1, 后面又说(2,1) = 10

#include <stdio.h>
#include <string.h>
#define inf 0x3fffffff
#define maxn 250

int m, n, sink, ssource, ssink; // m rows, n columns
int G[maxn][maxn], G0[maxn][maxn], flow[maxn][maxn];
int low[maxn][maxn], high[maxn][maxn];
int in[maxn], out[maxn], Layer[maxn], que[maxn];
bool vis[maxn];

int min(int a, int b) {
    return a > b ? b : a;
}

int max(int a, int b) {
    return a < b ? b : a;
}

bool countLayer() {
    memset(Layer, 0, sizeof(Layer));
    int i, now, id = 0, front = 0;
    Layer[ssource] = 1; que[id++] = ssource;
    while(front < id) {
        now = que[front++];
        for(i = 0; i <= ssink; ++i)
            if(G[now][i] > 0 && !Layer[i]) {
                Layer[i] = Layer[now] + 1;
                if(i == ssink) return true;
                else que[id++] = i;
            }
    }
    return false;
}

int Dinic() {
    int maxFlow = 0, minCut, pos, i, now, u, v, id = 0;
    while(countLayer()) {
        memset(vis, 0, sizeof(vis));
        vis[ssource] = 1; que[id++] = ssource;
        while(id) {
            now = que[id - 1];
            if(now == ssink) {
                minCut = inf;
                for(i = 1; i < id; ++i) {
                    u = que[i - 1];
                    v = que[i];
                    if(minCut > G[u][v]) {
                        minCut = G[u][v];
                        pos = u;
                    }
                }
                maxFlow += minCut;
                for(i = 1; i < id; ++i) {
                    u = que[i - 1];
                    v = que[i];
                    G[u][v] -= minCut;
                    G[v][u] += minCut;
                    flow[u][v] += minCut;
                    flow[v][u] -= minCut;
                }
                while(que[id - 1] != pos)
                    vis[que[--id]] = 0;
            } else {
                for(i = 0; i <= ssink; ++i) {
                    if(G[now][i] > 0 && Layer[now] + 1 == Layer[i] && !vis[i]) {
                        vis[i] = 1; que[id++] = i; break;
                    }
                }
                if(i > ssink) --id;
            }
        }
    }
    return maxFlow;
}

void solve() {
    int i, j, sum = 0;
    for(i = 0; i <= sink; ++i)
        for(j = 0; j <= sink; ++j) {
            G[i][j] = high[i][j] - low[i][j];
            out[i] += low[i][j];
            in[j] += low[i][j];
            sum += low[i][j];
        }
    for(i = 0; i <= sink; ++i) {
        G[ssource][i] = in[i];
        G[i][ssink] = out[i];
    }
    // memcpy(G0, G, sizeof(G));
    G[sink][0] = inf;
    if(sum != Dinic()) {
        printf("IMPOSSIBLE\n");
        return;
    }
    G[sink][0] = G[0][sink] = 0;
    for(i = 1; i <= m; ++i) {
        // printf("%d", G0[i][1 + m] - G[i][1 + m] + low[i][1 + m]);
        printf("%d", flow[i][1 + m] + low[i][1 + m]);
        for(j = 2; j <= n; ++j)
            printf(" %d", flow[i][j + m] + low[i][j + m]);
        printf("\n");
    }
}

int main() {
    // freopen("POJ2396.txt", "r", stdin);
    // freopen("ans1.txt", "w", stdout);
    int t, c, x, y, z, i, j;
    char ch;
    scanf("%d", &t);
    while(t--) {
        memset(G, 0, sizeof(G));
        memset(low, 0, sizeof(low));
        memset(high, 0, sizeof(high));
        memset(out, 0, sizeof(out));
        memset(in, 0, sizeof(in));
        memset(flow, 0, sizeof(flow));
        scanf("%d%d", &m, &n);
        sink = m + n + 1;
        ssource = sink + 1;
        ssink = ssource + 1;
        for(i = 1; i <= m; ++i) {
            scanf("%d", &z);
            low[0][i] = high[0][i] = z;
        }
        for(i = 1; i <= n; ++i) {
            scanf("%d", &z);
            low[m + i][sink] = high[m + i][sink] = z;
        }
        for(i = 1; i <= m; ++i) {
            for(j = 1; j <= n; ++j) {
                high[i][j + m] = inf;
            }
        }
        scanf("%d", &c);
        while(c--) {
            scanf("%d%d %c %d", &x, &y, &ch, &z);
            if(!x && y) { // 所有行的第y个元素
                if(ch == '=') {
                    for(i = 1; i <= m; ++i)
                        low[i][m + y] = high[i][m + y] = z;
                } else if(ch == '<') {
                    for(i = 1; i <= m; ++i)
                        high[i][m + y] = min(z - 1, high[i][m + y]);
                } else {
                    for(i = 1; i <= m; ++i)
                        low[i][m + y] = max(z + 1, low[i][m + y]);
                }
            } else if(x && !y) {
                if(ch == '=') {
                    for(i = 1; i <= n; ++i)
                        low[x][m + i] = high[x][m + i] = z;
                } else if(ch == '<') {
                    for(i = 1; i <= n; ++i)
                        high[x][m + i] = min(high[x][m + i], z - 1);
                } else {
                    for(i = 1; i <= n; ++i)
                        low[x][m + i] = max(low[x][m + i], z + 1);
                }
            } else if(!x && !y) {
                for(i = 1; i <= m; ++i)
                    for(j = 1; j <= n; ++j) {
                        if(ch == '=')
                            low[i][m + j] = high[i][m + j] = z;
                        else if(ch == '<')
                            high[i][m + j] = min(high[i][m + j], z - 1);
                        else low[i][m + j] = max(low[i][m + j], z + 1);
                    }
            } else {
                if(ch == '=')
                    low[x][m + y] = high[x][m + y] = z;
                else if(ch == '<')
                    high[x][m + y] = min(high[x][m + y], z - 1);
                else low[x][m + y] = max(low[x][m + y], z + 1);
            }
        }
        solve();
        printf("\n");
    }
    return 0;
}
时间: 2024-11-22 22:14:30

POJ2396 Budget 【带下界的最大流】的相关文章

ZOJ 3229 Shoot the Bullet 有源有汇带下界的最大流

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3229 Shoot the Bullet Time Limit: 2 Seconds      Memory Limit: 32768 KB      Special Judge Gensokyo is a world which exists quietly beside ours, separated by a mystical border. It is a u

[BZOJ2502]清理雪道解题报告|带下界的最小流

滑雪场坐落在FJ省西北部的若干座山上. 从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向. 你的团队负责每周定时清理雪道.你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部.从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道. 由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务. 题意就是给定一张DAG,求每条边起码经过一次求覆盖所有边的最小路径条数

poj2396 Budget 有源汇上下界可行流

/** 题目:poj2396 Budget 链接:http://poj.org/problem?id=2396 题意: 给定一个n*m矩阵,矩阵元素未知.已知第1~n行的元素和,第1~m列的元素和.以及元素的一些数据范围. 求一个可行的矩阵. 思路: 联想到以前没有下届的做法,用一个s连接所有的行节点,容量为该行的和,所有的列节点连接t,容量为该列的和. 所有的行节点连接所有的列节点,容量为无穷,然后求s到t的最大流.如果从s出发的弧都是满载的,那么有解. 所有行到所有列的flow为对应的行列位

zoj1994 / poj2396 Budget 有上下界可行流求解

题目链接: zoj1994 题目描述: 现在要针对多赛区竞赛制定一个预算,该预算是一个行代表不同种类支出.列代表不同赛区支出的矩阵.组委会曾经开会讨论过各类支出的总和,以及各赛区所需支出的总和.另外,组委会还讨论了一些特殊的约束条件:例如,有人提出计算机中心至少需要1000K 里亚尔(伊朗货币),用于购买食物:也有人提出Sharif 赛区用于购买体恤衫的费用不能超过30000K 里亚尔.组委会的任务是制定一个满足所有约束条件且行列和满足要求的预算. 解题报告: 该题解题关键在于建图, 将行置于左

POJ 2396 Budget (有源汇有上下界的可行流)

POJ 2396 Budget 链接:http://poj.org/problem?id=2396 题意:给定一个M*N的矩阵,给定每行每列的和,以及其中一些值的限定条件,问能否构成一个可行的矩阵. 思路: 添加一个源点,向每行连边,每条边的上下界都为该行的和:添加一个汇点,每列向汇点连边,边的上下界都为该列的和.然后每行向每列连边,边的上下界一开始为(0,INF),之后通过一些限定条件更新. 现在问题成了求一个有源汇有上下界的可行流.只需要再添加一个超级源点,一个超级汇点,并且将原图的汇点向源

ZOJ 2314 带上下界的可行流

对于无源汇问题,方法有两种. 1 从边的角度来处理. 新建超级源汇, 对于每一条有下界的边,x->y, 建立有向边 超级源->y ,容量为x->y下界,建立有向边 x-> 超级汇,容量为x->y下界.建立有向边 x->y,容量为x->y的上界减下界. 2 从点的角度来处理. 新建超级源汇,对于每个点流进的下界和为 in, 流出此点的下界和为out.如果in > out. 建立有向边 超级源->i,容量为in-out.反之,建立有向边 i->超级汇

【BZOJ-2502】清理雪道 有上下界的网络流(有下界的最小流)

2502: 清理雪道 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 594  Solved: 318[Submit][Status][Discuss] Description 滑雪场坐落在FJ省西北部的若干座山上. 从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向. 你的团队负责每周定时清理雪道.你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部.从降落的地点出

POJ 3801/HDU 3157 Crazy Circuits | 有下界的最小流

题目: POJ最近总是炸 所以还是用HDU吧http://acm.hdu.edu.cn/showproblem.php?pid=3157 题解: 题很长,但其实就是给个有源汇带下界网络流(+是源,-是汇),求最小流 求法: 1.模仿可行流建图,但是不加t到s的INF边 2.跑最大流 3.加t到sINF边 4.跑最大流 5.如果两次答案相加不等于sum,无解; 6.如果有解,t到s的反边流量就是答案 #include<cstdio> #include<algorithm> #incl

zoj 3229 有源汇有上下界的最大流模板题

/*坑啊,pe的程序在zoj上原来是wa. 题目大意:一个屌丝给m个女神拍照.计划拍照n天,每一天屌丝最多个C个女神拍照,每天拍照数不能超过D张,并且给每一个女神i拍照有数量限制[Li,Ri], 对于每一个女神n天的拍照总和不能超过Gi,假设有解求屌丝最多能拍多少张照,并求每天给相应女神拍多少张照:否则输出-1. 解题思路:增设一源点st,汇点sd.st到第i天连一条上界为Di下界为0的边,每一个女神到汇点连一条下界为Gi上界为oo的边,对于每一天,当天到第i个女孩连一条[Li.Ri]的边. 建