链接:http://poj.org/problem?id=2396
题意:给一个n*m的矩阵,给出每行的总和以及每列的总和,再给出某些位置的最小或最大限制,问是否存在可能的矩阵,如果存在输出一种矩阵信息。
思路:这是一个有源汇的上下界可行流,对于这种题,从汇点连一条弧到源点,容量为INF,这不会影响流量平衡条件,并且此时原图转换为了无源汇的上下界可行流,剩下的做法和无源汇一样。
建图:原图源点src连向每个行顶点,容量为每行的和,每个列顶点连向汇点,容量为每个列顶点的和,行顶点和列顶点间也各有一条弧,初始容量无下界、无上界,输入时再更新。最后连一条汇点指向源点的容量为INF的弧,剩下就是无源汇的做法。
这道题细节还是挺多的,初始化挫了WA出了翔。还有我在POJ上C++交TLE了,去ZOJ上交却过了,再回POJ用G++交才AC,不明觉厉。
isap代码
#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 100100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define seed 131
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson r,m+1,rt<<1|1
struct node{
int u,v,w,next;
}edge[20000];
int head[250],dist[250],cur[250],fa[250],num[250];
int low[300][300],upp[300][300],D[250];
int n,m,cnt,nn,src,sink,supersrc,supersink;
void add_edge(int a,int b,int c){
edge[cnt].u = a;
edge[cnt].v = b;
edge[cnt].w = c;
edge[cnt].next = head[a];
head[a] = cnt++;
}
void build_graph(){
int i,j;
for(i=1;i<=n;i++){
for(j=n+1;j<=n+m;j++){
D[i] -= low[i][j];
D[j] += low[i][j];
add_edge(i,j,upp[i][j]-low[i][j]);
add_edge(j,i,0);
}
}
add_edge(sink,src,INF);
add_edge(src,sink,0);
for(i=0;i<=n+m+1;i++){
if(D[i]==0) continue;
else if(D[i]>0){
add_edge(supersrc,i,D[i]);
add_edge(i,supersrc,0);
}
else{
add_edge(i,supersink,-D[i]);
add_edge(supersink,i,0);
}
}
}
void bfs()
{
int x,i,j;
queue<int> q;
memset(dist,-1,sizeof(dist));
q.push(supersink);
dist[supersink] = 0;
while(!q.empty()){
x = q.front();
q.pop();
for(i=head[x];i!=-1;i=edge[i].next){
if(dist[edge[i].v]<0){
dist[edge[i].v] = dist[x] + 1;
q.push(edge[i].v);
}
}
}
}
int augment()
{
int x=supersink,a=INF;
while(x!=supersrc){
a = min(a,edge[fa[x]].w);
x = edge[fa[x]].u;
}
x=supersink;
while(x!=supersrc){
edge[fa[x]].w -= a;
edge[fa[x]^1].w += a;
x = edge[fa[x]].u;
}
return a;
}
int isap()
{
int i,x,ok,minm,flow=0;
memset(num,0,sizeof(num));
bfs();
for(i=0;i<=nn+1;i++) num[dist[i]]++;
for(i=0;i<=nn+1;i++) cur[i] = head[i];
x=supersrc;
while(dist[supersrc]<nn){
if(x==supersink){
flow += augment();
x = supersrc;
}
ok=0;
for(i=cur[x];i!=-1;i=edge[i].next){
if(edge[i].w && dist[x]==dist[edge[i].v]+1){
ok=1;
fa[edge[i].v] = i;
cur[x] = i;
x = edge[i].v;
break;
}
}
if(!ok){
minm = nn;
for(i=head[x];i!=-1;i=edge[i].next)
if(edge[i].w && dist[edge[i].v]<minm) minm=dist[edge[i].v];
if(--num[dist[x]]==0)break;
num[dist[x]=minm+1]++;
cur[x]=head[x];
if(x!=supersrc) x=edge[fa[x]].u;
}
}
return flow;
}
int main(){
int t,q,i,j;
int a,b,c,d;
char str[5];
scanf("%d",&t);
int cas = 0;
while(t--){
if(!cas) cas = 1;
else puts("");
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
memset(D,0,sizeof(D));
cnt = 0;
src = 0;
sink = n + m + 1;
supersrc = sink + 1;
supersink = sink + 2;
nn = sink + 3;
for(i=0;i<=n+3;i++){
for(j=n+1;j<=n+m+3;j++){
low[i][j] = 0;
upp[i][j] = INF;
}
}
for(i=1;i<=n;i++){
scanf("%d",&a);
D[src] -= a;
D[i] += a;
}
for(i=n+1;i<=n+m;i++){
scanf("%d",&a);
D[i] -= a;
D[sink] += a;
}
int r1,r2,c1,c2;
scanf("%d",&q);
while(q--){
scanf("%d%d%s%d",&a,&b,str,&c);
if(a==0){
r1 = 1;
r2 = n;
}
else r1 = r2 = a;
if(b==0){
c1 = n + 1;
c2 = n + m;
}
else c1 = c2 = b + n;
for(i=r1;i<=r2;i++){
for(j=c1;j<=c2;j++){
if(str[0]=='<') upp[i][j] = min(c-1,upp[i][j]);
else if(str[0]=='>') low[i][j] = max(c+1,low[i][j]);
else{
low[i][j] = max(c,low[i][j]);
upp[i][j] = min(c,upp[i][j]);
}
}
}
}
build_graph();
isap();
int flag = 0;
for(i=head[supersrc];i!=-1;i=edge[i].next){
if(edge[i].w!=0){
flag = 1;
break;
}
}
if(flag) puts("IMPOSSIBLE");
else{
for(i=1;i<=n;i++){
for(j=1;j<m;j++){
printf("%d ",edge[(((i-1)*m+j-1)*2)^1].w+low[i][j+n]);
}
printf("%d\n",edge[(((i-1)*m+j-1)*2)^1].w+low[i][j+n]);
}
}
}
return 0;
}