POJ2396:Budget(带下界的网络流)
Budget
Time Limit: 3000MS | Memory Limit: 65536K | |||
Total Submissions: 8946 | Accepted: 3327 | Special Judge |
题目链接:http://poj.org/problem?id=2396
Description:
We are supposed to make a budget proposal for this multi-site competition. The budget proposal is a matrix where the rows represent different kinds of expenses and the columns represent different sites. We had a meeting about this, some time ago where we discussed the sums over different kinds of expenses and sums over different sites. There was also some talk about special constraints: someone mentioned that Computer Center would need at least 2000K Rials for food and someone from Sharif Authorities argued they wouldn't use more than 30000K Rials for T-shirts. Anyway, we are sure there was more; we will go and try to find some notes from that meeting.
And, by the way, no one really reads budget proposals anyway, so we'll just have to make sure that it sums up properly and meets all constraints.
Input:
The first line of the input contains an integer N, giving the number of test cases. The next line is empty, then, test cases follow: The first line of each test case contains two integers, m and n, giving the number of rows and columns (m <= 200, n <= 20). The second line contains m integers, giving the row sums of the matrix. The third line contains n integers, giving the column sums of the matrix. The fourth line contains an integer c (c < 1000) giving the number of constraints. The next c lines contain the constraints. There is an empty line after each test case.
Each constraint consists of two integers r and q, specifying some entry (or entries) in the matrix (the upper left corner is 1 1 and 0 is interpreted as "ALL", i.e. 4 0 means all entries on the fourth row and 0 0 means the entire matrix), one element from the set {<, =, >} and one integer v, with the obvious interpretation. For instance, the constraint 1 2 > 5 means that the cell in the 1st row and 2nd column must have an entry strictly greater than 5, and the constraint 4 0 = 3 means that all elements in the fourth row should be equal to 3.
Output:
For each case output a matrix of non-negative integers meeting the above constraints or the string "IMPOSSIBLE" if no legal solution exists. Put one empty line between matrices.
Sample Input:
2 2 3 8 10 5 6 7 4 0 2 > 2 2 1 = 3 2 3 > 2 2 3 < 5 2 2 4 5 6 7 1 1 1 > 10
Sample Output:
2 3 3 3 3 4 IMPOSSIBLE
题意:
给出n*m的矩阵,以及每行每列的和。然后给出k个限制条件,格式为x y c w。
如果x,y代表横纵坐标,如果x=0则代表所有的横坐标,y=0则代表所有的纵坐标,c表示容量限制,可能大于、小于或等于,w就是具体的数值。
最后要你输出一种满足题中条件的情况,如果不满足则输出"IMPOSSIBLE"。
题解:
这题可以用带上下界有缘有汇网络流的标准解法就可以做,直接百度一下就好啦。
但我似乎是另外一种方式,就在这里大致说说我的思路吧。
对于"=",那么之后我们不连这里的横纵坐标,直接给答案数组赋值并且横和纵和减去相应的数。对于大于和小于,我们更新数组就行了。
最后建边的时候,边的容量为最大值减去最小值,对于一条边连接的两个点(x,y分别表示横和列),如果这条边有最小值,x,y都减去这个最小值即可。
然后跑个最大流就行了,输出路径的时候答案应该加上之前减去的最小值。
我这个思路正确性应该没问题,但代码实现出来有点复杂,我调了半天,说下注意的几个问题吧:
1.输入数据可能有矛盾,注意判断; 2.输入数据可能有重复,我在输入"="的时候对数组进行了修改,一开始没注意这点,就多减了.... 3.将>x看成>=x+1好处理一些,"<"也类似; 4.由于二分图右侧的点编号为n+x,所以注意下数组的索引...
总之细心点就好了~
给出我复杂的代码...
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <queue> #define s 0 #define t 300 #define INF 0x3f3f3f3f using namespace std; typedef long long ll; const int N = 205,M = 25,MAXN = 305; int T; int n,m,tot; int mx[N][M],mn[N][M],head[MAXN],r[N],c[M],ans[N][M],d[MAXN]; struct Edge{ int v,next,c; }e[(MAXN*MAXN)<<1]; void adde(int u,int v,int c){ e[tot].v=v;e[tot].next=head[u];e[tot].c=c;head[u]=tot++; e[tot].v=u;e[tot].next=head[v];e[tot].c=0;head[v]=tot++; } bool bfs(int S,int T){ memset(d,0,sizeof(d));d[S]=1; queue <int > q;q.push(S); while(!q.empty()){ int u=q.front();q.pop(); for(int i=head[u];i!=-1;i=e[i].next){ int v=e[i].v; if(!d[v] && e[i].c>0){ d[v]=d[u]+1; q.push(v); } } } return d[T]!=0; } int dfs(int S,int a){ int flow=0,f; if(S==t || a==0) return a; for(int i=head[S];i!=-1;i=e[i].next){ int v=e[i].v; if(d[v]!=d[S]+1) continue ; f=dfs(v,min(a,e[i].c)); if(f){ e[i].c-=f; e[i^1].c+=f; flow+=f; a-=f; if(a==0) break; } } if(!flow) d[S]=-1; return flow; } int Dinic(){ int max_flow=0; while(bfs(0,t)) max_flow+=dfs(0,INF); return max_flow; } int main(){ //freopen("2.txt","w",stdout); cin>>T; while(T--){ int ok=1; scanf("%d%d",&n,&m); memset(mn,0,sizeof(mn)); memset(mx,INF,sizeof(mx)); memset(ans,0,sizeof(ans)); for(int i=1;i<=n;i++) scanf("%d",&r[i]); for(int i=1;i<=m;i++) scanf("%d",&c[i]); int tt; scanf("%d",&tt); while(tt--){ int u,v,w;char C; scanf("%d %d %c %d",&u,&v,&C,&w); if(C=='='){ if(u==0 && v){ for(int i=1;i<=n;i++){ if(ans[i][v]){ if(ans[i][v]!=w) ok=0; continue ; } ans[i][v]=w; r[i]-=w; c[v]-=w; } }else if(v==0 && u){ for(int i=1;i<=m;i++){ if(ans[u][i]){ if(ans[u][i]!=w) ok=0; continue ; } ans[u][i]=w; c[i]-=w; r[u]-=w; } }else if(!v && !u){ int tmp = 0; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(ans[i][j]){ if(ans[i][j]!=w) ok=0; continue ; } ans[i][j]=w; r[i]-=w;c[j]-=w; } } }else{ if(ans[u][v]){ if(ans[u][v]!=w) ok=0; continue ; } r[u]-=w;c[v]-=w; ans[u][v]=w; } }else if(C=='>'){ if(u==0 && v){ for(int i=1;i<=n;i++) mn[i][v]=max(mn[i][v],w+1); }else if(v==0 && u){ for(int i=1;i<=m;i++) mn[u][i]=max(mn[u][i],w+1); }else if(!v && !u){ for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) mn[i][j]=max(mn[i][j],w+1); }else mn[u][v]=max(mn[u][v],w+1); }else{ if(u==0 && v){ for(int i=1;i<=n;i++) mx[i][v]=min(mx[i][v],w-1); }else if(v==0 && u){ for(int i=1;i<=m;i++) mx[u][i]=min(mx[u][i],w-1); }else if(!v && !u){ for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) mx[i][j]=min(mx[i][j],w-1); }else mx[u][v]=min(mx[u][v],w-1); } } memset(head,-1,sizeof(head));tot=0; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(mx[i][j]<mn[i][j])ok=0; if(ans[i][j]){ if(ans[i][j]<mn[i][j]||ans[i][j]>mx[i][j]) ok=0; continue ; } r[i]-=mn[i][j]; c[j]-=mn[i][j]; adde(i,j+n,mx[i][j]-mn[i][j]); if(r[i]<0 || c[j]<0) ok=0; } } int sum1=0,sum2=0; for(int i=1;i<=n;i++) sum1+=r[i]; for(int i=1;i<=m;i++) sum2+=c[i]; if(sum1!=sum2) ok=0; if(!ok){ puts("IMPOSSIBLE"); continue ; } for(int i=1;i<=n;i++) adde(s,i,r[i]); for(int i=1;i<=m;i++) adde(n+i,t,c[i]); int max_flow=Dinic(); for(int i=head[s];i!=-1;i=e[i].next){ if(e[i].c!=0) ok=0; } if(!ok) puts("IMPOSSIBLE"); else{ for(int u=1;u<=n;u++){ for(int j=head[u];j!=-1;j=e[j].next){ if(e[j].v<=n) continue ; int v=e[j].v-n; if(ans[u][v]) continue ; ans[u][v]=ans[u][v]+mx[u][v]-e[j].c; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cout<<ans[i][j]<<" "; } cout<<endl; } cout<<endl; } } return 0; }
重要的是自信,一旦有了自信,人就会赢得一切。