一.原题链接: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(); } }