链接: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 - 1; 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; }
POJ2396&ZOJ1994--Budget【有源汇上下界可行流】
时间: 2024-10-22 13:18:10