| Time Limit: 3000MS | Memory Limit: 65536K | |||
| Total Submissions: 5962 | Accepted: 2266 | Special Judge | ||
Description
Input
Output
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
比方规定第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;
}
原文:http://www.cnblogs.com/tlnshuju/p/6853384.html