pku2396:
这个题是个典型的容量有上下界的网络流问题。
假设您已经对最大流的原理很了解,那么请继续看:
关于这种问题的解法,请看这篇论文,讲的很好。
http://wenku.baidu.com/view/0f3b691c59eef8c75fbfb35c.html
如果这篇论文看得没有问题了,那么我们来谈一下建图。
显然所有行的和与列的和是相同的,这是什么——网络流的流量平衡。
但是行和列中每个元素怎样限定呢?一种做法是:将每行、每列及每个元素看成一个点,然后把每个点拆成两个点,中间限制流量。。。。但是这样做点数有2000多个。。。。有点太大了~~ 第二种做法:只将每一行和每一列看成一个节点,中间连边代表元素,然后给边加上上下界。看看是否存在可行流,如果存在就输出一个,否则impossible。
注意:
如果建图过程中一条边的上界<下界——无解
如果每列总和与每行总和不相等——循环流不守恒——无解
f(s,i)<c(s,i)或者f(i,t)<c(i,t)——新网络没有满流,也就是源网络存在某些边无法满足下界约束或者上界约束——无解
此题主要过程在于建图,建好了图直接dinic或者sap都行~注意是多组数据啊,每次开始前记得初始化,我debug了好一会儿才发现res数组忘记初始化了,泪奔~~。
代码比一般题有一点点多,打了40+分钟才打完,但也不是特别多,加上debug的过程才260+
测试数据地址:http://www.ida.liu.se/projects/progcontest/progsm/2003/
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
usingnamespace std;
constint N =250;
constint inf =1000000;
int n, m, s, t, sumr[N], sumc[23], queue[N], lab[N], res[N][N], up[N][N], low[N][N], flow[N][N];
void initData()
{
int i, j, x, y, z, q;
char c;
memset(low, 0, sizeof(low));
memset(up, 0, sizeof(up));
scanf("%d%d", &n, &m);
for(i =1; i <= n; i++)
{
scanf("%d", sumr+i);
up[0][i] = low[0][i] = sumr[i];
}
for(i =1; i <= m; i++)
{
scanf("%d", sumc+i);
up[i+n][n+m+1] = low[i+n][n+m+1] = sumc[i];
}
for(i =1; i <= n; i++)
for(j =1; j <= m; j++)
up[i][j+n] = inf;
scanf("%d", &q);
while(q--)
{
scanf("%d%d %c%d", &x, &y, &c, &z);
switch(c)
{
case'>':
{
z++;
if(x==0&& y!=0)
{
for(i =1; i <= n; i++)
low[i][y+n] = max(low[i][y+n], z);
break;
}
if(x!=0&& y==0)
{
for(j =1; j <= m; j++)
low[x][j+n] = max(low[x][j+n], z);
break;
}
if(x==0&& y==0)
{
for(i =1; i <= n; i++)
for(j =1; j <= m; j++)
low[i][j+n] = max(low[i][j+n], z);
break;
}
if(x!=0&& y!=0)
{
low[x][y+n] = max(low[x][y+n], z);
break;
}
}
case'<':
{
z--;
if(x==0&& y!=0)
{
for(i =1; i <= n; i++)
up[i][y+n] = min(up[i][y+n], z);
break;
}
if(x!=0&& y==0)
{
for(j =1; j <= m; j++)
up[x][j+n] = min(up[x][j+n], z);
break;
}
if(x==0&& y==0)
{
for(i =1; i <= n; i++)
for(j =1; j <= m; j++)
up[i][j+n] = min(up[i][j+n], z);
break;
}
if(x!=0&& y!=0)
{
up[x][y+n] = min(up[x][y+n], z);
break;
}
}
case'=':
{
if(x==0&& y!=0)
{
for(i =1; i <= n; i++)
{
up[i][y+n] = min(up[i][y+n], z);
low[i][y+n] = max(low[i][y+n], z);
}
break;
}
if(x!=0&& y==0)
{
for(j =1; j <= m; j++)
{
up[x][j+n] = min(up[x][j+n], z);
low[x][j+n] = max(low[x][j+n], z);
}
break;
}
if(x==0&& y==0)
{
for(i =1; i <= n; i++)
for(j =1; j <= m; j++)
{
up[i][j+n] = min(up[i][j+n], z);
low[i][j+n] = max(low[i][j+n], z);
}
break;
}
if(x!=0&& y!=0)
{
up[x][y+n] = min(up[x][y+n], z);
low[x][y+n] = max(low[x][y+n], z);
break;
}
break;
}
}
}
}
bool check()
{
int i, j, t1, t2, tot = n+m+1;
t1 = t2 =0;
for(i =1; i <= n; i++) t1 += sumr[i];
for(j =1; j <= m; j++) t2 += sumc[j];
if(t1 != t2) returnfalse;
up[tot][0] = low[tot][0] = t1;
for(i =1; i <= n; i++)
for(j =1; j <= m; j++)
if(low[i][j+n] > up[i][j+n])
returnfalse;
returntrue;
}
void buildGraph()
{
int i, j, tmp;
s = n+m+2;
t = n+m+3;
memset(res, 0, sizeof(res));
for(i =0; i < s; i++)
{
tmp =0;
for(j =0; j < s; j++) tmp += low[j][i];
for(j =0; j < s; j++) tmp -= low[i][j];
if(tmp >0) res[s][i] = tmp;
elseif(tmp <0)
res[i][t] =-tmp;
}
for(i =0; i < s; i++)
for(j =0; j < s; j++)
res[i][j] = up[i][j] - low[i][j];
memset(flow, 0, sizeof(flow));
}
bool bfs(int s, int t)
{
int head, tail, i, u;
memset(lab, -1, sizeof(lab));
head = tail =0;
queue[0] = s;
lab[s] =0;
while(head <= tail)
{
u = queue[head++];
for(i =0; i <= t; i++)
if(res[u][i]>0&& lab[i]==-1)
{
lab[i] = lab[u] +1;
queue[++tail] = i;
}
if(lab[t] !=-1) returntrue;
}
returnfalse;
}
int dinicDfs(int delta, int u)
{
int i, sum =0, tmp;
if(u == t) return delta;
for(i =0; i <= t; i++)
if(res[u][i]>0&& lab[i]==lab[u]+1)
{
tmp = dinicDfs(min(delta, res[u][i]), i);
sum += tmp;
delta -= tmp;
res[u][i] -= tmp;
res[i][u] += tmp;
flow[u][i] += tmp;
flow[i][u] -= tmp;
}
return sum;
}
void maxFlow(int s, int t)
{
int tmp;
while(bfs(s, t))
tmp = dinicDfs(inf, s);
}
void deal()
{
bool flag =true;
int i, j;
for(i =0; i < s; i++)
if(!(res[s][i]==0&& res[i][t]==0))
{
flag =false;
break;
}
if(!flag) printf("IMPOSSIBLE\n");
else
{
for(i =1; i <= n; i++)
{
for(j =1; j < m; j++) printf("%d ", flow[i][j+n]+low[i][j+n]);
printf("%d\n", flow[i][m+n]+low[i][m+n]);
}
}
}
void debug()
{
int i, j;
for(i =1; i <= n; i++)
for(j =1; j <= m; j++)
printf("%d -> %d : %d %d\n", i, j, low[i][j+n], up[i][j+n]);
}
int main()
{
int Case, ct =0;
freopen("data.txt", "r", stdin);
freopen("ans.txt", "w", stdout);
scanf("%d", &Case);
while(Case--)
{
if(ct) printf("\n");
initData();
// debug();
if(check())
{
buildGraph();
maxFlow(s, t);
deal();
}
else printf("IMPOSSIBLE\n");
ct++;
}
return0;
}