一.原题链接:http://poj.org/problem?id=2396
二.题目大意:给你一个矩阵,告诉你每一行的和是多少,每一列的和是多少,在给一些限制条件限制每个格子里面的数的上下界。让你输出这个矩阵,如果没法输出就输出IMPOSSIBILE
三.思路:这题是流量有上下界的网络流,别问怎么看出来的。
建图如下:
1.把每一行看做一个点, 把每一列看做一个点。
2.建立一个源点s,连接s与每一行,容量上限下限设为该行和。
3.建立一个汇点t,连接每一列与t,容量上限下限设为该列和。
4.对于每一行跟每一列,先连一条下限为0,上限为无穷大的边,然后根据给出的条件修改边上下界。
是不是答案就很明显了,该模型有可行流就有解,解为每行和每列流量。
有汇源的流量有上下界的网络流求解思路:连一条边从T->S流量限制为0~INF,直接转化为无汇源的流量有上下界的网络流求解。为什么要连这条边呢?为了让流量守恒。
无汇源的流量有上下界的网络流求解详情请看:http://blog.youkuaiyun.com/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();
}
}