POJ2396 Budget

一.原题链接:http://poj.org/problem?id=2396

二.题目大意:给你一个矩阵,告诉你每一行的和是多少,每一列的和是多少,在给一些限制条件限制每个格子里面的数的上下界。让你输出这个矩阵,如果没法输出就输出IMPOSSIBILE

三.思路:这题是流量有上下界的网络流,别问怎么看出来的。

建图如下:

1.把每一行看做一个点, 把每一列看做一个点。

2.建立一个源点s,连接s与每一行,容量上限下限设为该行和。

3.建立一个汇点t,连接每一列与t,容量上限下限设为该列和。

4.对于每一行跟每一列,先连一条下限为0,上限为无穷大的边,然后根据给出的条件修改边上下界。

是不是答案就很明显了,该模型有可行流就有解,解为每行和每列流量。

有汇源的流量有上下界的网络流求解思路:连一条边从T->S流量限制为0~INF,直接转化为无汇源的流量有上下界的网络流求解。为什么要连这条边呢?为了让流量守恒。

无汇源的流量有上下界的网络流求解详情请看:http://blog.csdn.net/h992109898/article/details/51245426

最后输出结果的时候。就是伴随网络的流量值(保存在反向弧里面)加上最低的流量。由于我添加边顺序的原因,我最后要反向输出,当然你也可以编个号排个序。

四.坑点:我用Dinic超时了,可能是我写丑了,不过用最高标号居然110MS过了2333。

五.代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int MAX_N = 22, MAX_M = 243,
          INF = 0x3f3f3f3f;

class Push_Relabel
{
public:
    struct node
    {
        int x, h;
        bool friend operator <(const node &a,const node &b)
        {
            return a.h<b.h;
        }
    };

    struct Edge
    {
        int v, weigt, next;
    };

    Edge edges[MAX_M*MAX_M];
    int s, t, maxFlow, cnt,
        head[MAX_M], H[MAX_M], EF[MAX_M];
    priority_queue <node> que;

    void init(int is, int it, int nodeNum)
    {
        memset(edges, 0, sizeof(edges));
        memset(H, 0, sizeof(H));
        memset(EF, 0, sizeof(EF));
        memset(head, -1, sizeof(head));
        maxFlow = 0;
        cnt = 0;
        s = is, t = it;
        EF[s] = INF;
        EF[t] = -INF;
        H[s] = nodeNum;
    }

    void addEdge(int u, int v, int weight)
    {
        edges[cnt] = (Edge){v, weight, head[u]};
        head[u] = cnt++;
        edges[cnt] = (Edge){u, 0, head[v]};
        head[v] = cnt++;
    }

    void Push(int cur)
    {
        int i, temp, v;
        node tmp;
        for(i = head[cur]; i != -1; i = edges[i].next){
            v = edges[i].v;
            temp = min(edges[i].weigt, EF[cur]);
            if(temp > 0 &&(cur == s || 1==H[cur]-H[v])){
                edges[i].weigt -= temp, edges[i^1].weigt += temp;
                EF[cur] -= temp, EF[v] += temp;
                if(v == t)
                    maxFlow += temp;
                if(v != s && v != t){
                    tmp.x = v, tmp.h = H[v];
                    que.push(tmp);
                }
            }
        }
    }

    void Relabel(int cur)
    {
        node tmp;
        if(cur != s && cur != t && EF[cur] > 0){
            H[cur]++;
            tmp.h = H[cur], tmp.x = cur;
            que.push(tmp);
        }
    }

    int ans()
    {
        node cur{s, H[s]};
        que.push(cur);
        while(!que.empty()){
            cur = que.top();
            que.pop();
            Push(cur.x);
            Relabel(cur.x);
        }
        return maxFlow;
    }
}G;

int low[MAX_M][MAX_M], up[MAX_M][MAX_M], cnt[MAX_M],
    row, col, s, t;
bool ableSolve;

void init()
{
    ableSolve = true;
    s = row + col + 1, t = s + 1;
    memset(cnt, 0, sizeof(cnt));
    memset(low, 0, sizeof(low));
    memset(up, INF, sizeof(up));
    G.init(t + 1, t + 2, t + 2);
}

bool setLimted(int u, int v, char ch, int cap)
{
    switch(ch)
    {
    case '=':
        if(low[u][v] > cap || up[u][v] < cap)
                return false;
        low[u][v] = up[u][v] = cap;
        break;
    case '>':
        low[u][v] = max(low[u][v], cap + 1);
        break;
    case '<':
        up[u][v] = min(up[u][v], cap - 1);
        break;
    }

    if(low[u][v] > up[u][v])
        return false;

    return true;
}

void read()
{
    int i, j, cap, num, rowId, colId;
    char choose;
    for(i = 1; i <= row; i++){
        scanf("%d", &cap);
        low[s][i] = up[s][i] = cap;
    }

    for(i = 1; i <= col; i++){
        scanf("%d", &cap);
        low[i][t] = up[i][t] = cap;
    }

    scanf("%d", &num);

    while(num--){
        scanf("%d %d %c %d", &rowId, &colId, &choose, &cap);
        if(rowId && colId && ableSolve)
            ableSolve = setLimted(rowId, colId, choose, cap);
        else if(!rowId && colId && ableSolve)
            for(i = 1; i <= row; i++)
                ableSolve = setLimted(i, colId, choose, cap);
        else if(rowId && !colId && ableSolve)
            for(j = 1; j <= col; j++)
                ableSolve = setLimted(rowId, j, choose, cap);
        else if(ableSolve)
            for(i = 1; i <= row; i++)
                for(j = 1; j <= col; j++)
                    ableSolve = setLimted(i, j, choose, cap);
    }
}

bool buildG()
{
    int SS = t + 1, TT = t + 2, sum = 0, i, j;
    for(i = 1; i <= row; i++)
        for(j = 1; j <= col; j++){
            G.addEdge(i, j+row, up[i][j] - low[i][j]);
            cnt[i] -= low[i][j], cnt[j+row] += low[i][j];
        }

    for(i = 1; i <= row; i++){
        G.addEdge(s, i, 0);
        cnt[s] -= low[s][i];
        cnt[i] += low[s][i];
    }

    for(j = 1; j <= col; j++){
        G.addEdge(j+row, t, 0);
        cnt[j+row] -= low[j][t];
        cnt[t] += low[j][t];
    }

    G.addEdge(t, s, INF);

    for(i = 1; i <= t; i++)
        if(cnt[i] > 0){
            G.addEdge(SS, i, cnt[i]);
            sum += cnt[i];
        }
        else
            G.addEdge(i, TT, -cnt[i]);

    if(G.ans() != sum)
        return false;
    else
        return true;
}

void printG()
{
    int i, j, k, v, save[MAX_M][MAX_N];
    for(i = 1; i <= row; i++){
        k = 1;
        for(j = G.head[i]; j != -1; j = G.edges[j].next){
            v = G.edges[j].v;
            if(v >= row + 1 && v <= row + col)
                save[i][k++] = G.edges[j^1].weigt + low[i][v-row];
        }
    }

    for(i = 1; i <= row; i++){
        for(j = col; j > 0; j--)
            printf("%d ", save[i][j]);
        printf("\n");
    }
    printf("\n");
}

int main()
{
    //freopen("in.txt", "r", stdin);

    int test;
    scanf("%d", &test);

    while(test--){

        scanf("%d%d", &row, &col);
        init();
        read();
        if(ableSolve)
            ableSolve = buildG();
        if(!ableSolve){
            printf("IMPOSSIBLE\n");
            continue;
        }

        printG();
    }
}


你可能感兴趣的:(POJ2396 Budget)