这题的建图真恶心。好不容易写完后结果还wa了,顿时生无可恋啊,看了下discuss,说不能输出负数,最后不能输出多余的空行,我把这俩都改了,就AC了,虽说那里说这是在zoj不能ac的原因,不过在poj也适用,哈哈。
思路:每行为一个点,每列为一个点,给出的限制就是行列之间连线的流的上下界,初始下届为0,上界为INF。然后建好图之后,建立一个虚拟源点和虚拟汇点,源点和边连线,流量上下界为行的和,列和汇点连线,流量上下界为列的和。然后汇点向源点连接一条下界为0,上界INF的线,这就成了一个 无源汇上下界可行流 的问题。
#include <queue>
#include <vector>
#include <algorithm>
#include <stdio.h>
#include <string.h>
using namespace std;
const int MAXN = 300;
const int INF = 0x7f7f7f7f;
struct edge
{
edge() {}
edge(int _to, int _cap, int _rev, int _id)
:to(_to),cap(_cap),rev(_rev),id(_id){}
int to,cap,rev,id;
};
vector<edge> G[MAXN];
int level[MAXN];//分层
int iter[MAXN];//当前弧优化
void debug(int x)
{
printf("%d\n",x);
}
void addedge(int from, int to, int cap, int id)
{
// printf("%d ---- %d:%d\n",from,to,cap);
G[from].push_back(edge(to, cap, G[to].size(), 0));
G[to].push_back(edge(from, 0, G[from].size()-1, id));
}
//先分层,然后在分层图上dfs
void bfs(int s)
{
memset(level, -1, sizeof(level));
queue<int> que;
level[s] = 0;
que.push(s);
while(!que.empty())
{
int v = que.front();
que.pop();
for(int i = 0; i < G[v].size(); ++i)
{
edge& e = G[v][i];
if(e.cap > 0 && level[e.to] < 0)
{
level[e.to] = level[v] + 1;
que.push(e.to);
}
}
}
}
int dfs(int v, int t, int f)
{
if(v == t) return f;
for(int &i = iter[v]; i < G[v].size(); ++i)
{
edge &e = G[v][i];
if(e.cap > 0 && level[v] < level[e.to])
{
int d = dfs(e.to, t, min(f, e.cap));
if(d > 0)
{
// printf("%d->%d:%d\n",v,e.to,e.cap);
// debug(e.cap);
e.cap -= d;
// debug(e.cap);
// debug(G[e.to][e.rev].cap);
G[e.to][e.rev].cap += d;
// debug(G[e.to][e.rev].cap);
return d;
}
}
}
return 0;
}
int maxFlow(int s, int t)
{
int flow = 0;
while(true)
{
bfs(s);
if(level[t] < 0) return flow;
memset(iter,0,sizeof(iter));
int f;
while((f = dfs(s,t,INF)) > 0)
flow += f;
}
}
//这里n表示行数,m表示列数
int n,m,csa,s,t,S,T,sum;
int row[MAXN],col[MAXN];
int low[MAXN][MAXN];
int up[MAXN][MAXN];
int totFlow[MAXN];
int res[MAXN][MAXN];
bool flag = false;
void process(int r, int c, char ch, int ct)
{
if(r == 0 && c == 0)
{
if(ch == '>')
{
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
low[i][j] = max(low[i][j],ct+1);
}
else if(ch == '<')
{
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
up[i][j] = min(up[i][j],ct-1);
}
else
{
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
low[i][j] = up[i][j] = ct;
}
}
else if(r == 0)
{
if(ch == '>')
{
for(int i = 1; i <= n; ++i)
low[i][c] = max(low[i][c],ct+1);
}
else if(ch == '<')
{
for(int i = 1; i <= n; ++i)
up[i][c] = min(up[i][c],ct-1);
}
else
{
for(int i = 1; i <= n; ++i)
low[i][c] = up[i][c] = ct;
}
}
else if(c == 0)
{
if(ch == '>')
{
for(int i = 1; i <= m; ++i)
low[r][i] = max(low[r][i],ct+1);
}
else if(ch == '<')
{
for(int i = 1; i <= m; ++i)
up[r][i] = min(up[r][i],ct-1);
}
else
{
for(int i = 1; i <= m; ++i)
low[r][i] = up[r][i] = ct;
}
}
else//都不是0
{
if(ch == '>')
low[r][c] = max(low[r][c],ct+1);
else if(ch == '<')
up[r][c] = min(up[r][c],ct-1);
else
low[r][c] = up[r][c] = ct;
}
}
void read()
{
scanf("%d %d",&n,&m);
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= m; ++j)
{
low[i][j] = 0;
up[i][j] = INF;
}
}
for(int i = 1; i <= n; ++i)
{
scanf("%d",&row[i]);
if(row[i] < 0) flag = true;
}
for(int i = 1; i <= m; ++i)
{
scanf("%d",&col[i]);
if(col[i] < 0) flag = true;
}
scanf("%d",&csa);
char ch;
int r,c,ct;
for(int i = 0; i < csa; ++i)
{
scanf(" %d %d %c %d",&r,&c,&ch,&ct);
if(ch == '<' && ct < 0) flag = true;
process(r,c,ch,ct);
}
if(flag) return;
//建图
//虚拟源点和汇点
s = 0,t = n+m+1;
//超级虚拟原点和汇点
S = t+1,T = t+2;
addedge(t,s,INF,0);//下界为0,不用管
//ok 在这里已经建好了行和列之间的边
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= m; ++j)
{
addedge(i,j+n,up[i][j]-low[i][j],i*1000+j);
totFlow[i] -= low[i][j];
totFlow[j+n] += low[i][j];
}
}
//下边就是虚拟源点和虚拟汇点了
for(int i = 1; i <= n; ++i)
addedge(s,i,0,0),totFlow[i] += row[i],totFlow[s] -= row[i];//上下界都为row[i]
for(int i = 1; i <= m; ++i)
addedge(i+n,t,0,0),totFlow[i+n] -= col[i],totFlow[t] += col[i];//上下界都为col[i]
//以上就成了一个无源汇上下界循环流的网络
//下边添加补流,增加必要边
sum = 0;
for(int i = s; i <= t; ++i)
{
if(totFlow[i] < 0)
addedge(i,T,-totFlow[i],0);
else
{
sum += totFlow[i];
addedge(S,i,totFlow[i],0);
}
}
}
void solve()
{
if(flag)
{
puts("IMPOSSIBLE");
return;
}
int ret = maxFlow(S,T);
int r,c;
if(ret == sum)
{
for(int i = 1; i <= n+m; ++i)
{
for(int j = 0; j < G[i].size(); ++j)
{
if(G[i][j].id)
{
r = G[i][j].id/1000;
c = G[i][j].id%1000;
res[r][c] += (low[r][c]+G[i][j].cap);
}
}
}
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= m; ++j)
printf("%d ",res[i][j]);
printf("\n");
}
}
else
puts("IMPOSSIBLE");
}
void init()
{
flag = false;
memset(totFlow,0,sizeof(totFlow));
memset(res,0,sizeof(res));
}
void Clear()
{
for(int i = 0; i <= T; ++i)
G[i].clear();
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
read();
solve();
Clear();
if(T) printf("\n");
}
return 0;
}