思路题解:矩阵模型,模拟网络流,行、列标号为结点,构图,附加s,t,s连行标(容量上下限每行之和(必需以这个
值全部送过去),每个列标连向t(容量上下限每列之和)),其他每个行到列都有边(有限制的按限制
来,无限制的自己添加)。由于s->网络->t,若有解,总流量f必为
矩阵所有数之和,故添加边t-S,容量上下线为矩阵和sum,这样保证了每个点出入流相等,满足流量平衡,
转化为无源无汇有上下线可行流问题,在建立超级源点汇点ss,tt,按无源无汇法做一遍ss->tt最大流,
判断可行即可。可行输出方案。PS,若题目改为求有源有汇有限制最大流问题,可以在残量网络再走一次
s->t(原图源汇)最大流(solo可行的后悔边啥~)
此题,有源有汇有限制可行流问题,主要是建图,就是一个字烦!其一:0的时候要所有,行列为0要
讨论,其二,>,<,=符号的判定,讨论下,其三,重边,这个不是链前星锁解决那个重边,而是重边
是“且”的关系,如,先给上限,再来一边给下限!坑爹啊这是要!无法,hash判重吧,重了,再修改原来的
边,要搞清楚反向边(建图时跑第一次(第一次判断有无解)前)流量始终为0(提供后悔的,和之后没有
半毛钱关系)!至于算法,不再是问题,dinic跑的。
#include<iostream> //47ms,1A #include<cstdio> #include<queue> #include<vector> using namespace std; int n,m;const int inf=0x3f3f3f3f; int suminf[300];int sumouf[300]; int e[20000][5]; int head[300];int level[300];int vis[300]; int hash[250][300];int ans[250][300]; int nume=0; bool bfs() //dinic“d,bfs”,不用说了 { for(int i=0;i<n+m+4;i++) level[i]=vis[i]=0; vis[n+m+2]=1; queue<int>q;q.push(n+m+2); while(!q.empty()) { int cur=q.front();q.pop(); for(int i=head[cur];i!=-1;i=e[i][1]) { int v=e[i][0]; if(!vis[v]&&e[i][2]>0) { level[v]=level[cur]+1; vis[v]=1; if(v==m+n+3)return 1; q.push(v); } } } return vis[n+m+3]; } int dfs(int u,int minf) { if(u==n+m+3||minf==0){return minf;} int sumf=0,f; for(int i=head[u];i!=-1&&minf;i=e[i][1]) { int v=e[i][0]; if(level[v]==level[u]+1&&e[i][2]>0) { f=dfs(v,minf<e[i][2]?minf:e[i][2]); if(f==0)continue; e[i][2]-=f;e[i^1][2]+=f; minf-=f;sumf+=f; } } return sumf; } void dinic() { int sumflow=0; while(bfs()) { sumflow+=dfs(n+m+2,inf); } } bool check() //无源无汇的,出发点ss(超级源点)的边有一条不满流就无解,原因简单必需保证流量平衡(为之提供下限) { for(int i=head[n+m+2];i!=-1;i=e[i][1]) { if(e[i][2]!=0)return 0; } return 1; } int main() { int N; scanf("%d",&N); while(N--) //N组输入 { scanf(" %d%d",&n,&m); //忽略空行 nume=0; int sum=0,temp; bool mark=0; for(int i=0;i<=n+m+5;i++) { head[i]=-1; suminf[i]=sumouf[i]=0; } for(int i=0;i<=n;i++) for(int j=n+1;j<=n+m+1;j++) ans[i][j]=hash[i][j]=0; for(int i=1;i<=n;i++) //有源有汇的源点s { scanf("%d",&temp);sum+=temp; e[nume][0]=i;e[nume][1]=head[0];head[0]=nume; e[nume][2]=0;e[nume][3]=temp;e[nume++][4]=temp; suminf[i]+=temp;sumouf[0]+=temp; e[nume][0]=0;e[nume][1]=head[i];head[i]=nume; e[nume++][2]=0; } for(int i=n+1;i<=m+n;i++) //汇点t { scanf("%d",&temp); e[nume][0]=n+1+m;e[nume][1]=head[i];head[i]=nume; e[nume][2]=0;e[nume][3]=temp;e[nume++][4]=temp; suminf[n+m+1]+=temp;sumouf[i]+=temp; e[nume][0]=i;e[nume][1]=head[n+m+1];head[n+m+1]=nume; e[nume++][2]=0; } e[nume][0]=0;e[nume][1]=head[n+m+1];head[n+m+1]=nume; //添加t->s e[nume][2]=0;e[nume][3]=sum;e[nume++][4]=sum; suminf[0]+=sum;sumouf[n+m+1]+=sum; e[nume][0]=n+m+1;e[nume][1]=head[0];head[0]=nume; e[nume++][2]=0; int ca;scanf("%d",&ca); int row,col,lim;char cc; for(int i=0;i<ca;i++) //按条件建图 { scanf("%d%d %c %d",&row,&col,&cc,&lim); if(col!=0&&row==0) { if(cc=='=') for(int i=1;i<=n;i++) { if(hash[i][n+col]) //判重,下面一致 { int pp; for( pp=head[i];e[pp][0]!=n+col;pp=e[pp][1]) ; suminf[n+col]-=e[pp][3]; sumouf[i]-=e[pp][3]; if(lim>e[pp][3])e[pp][3]=lim; if(lim<e[pp][4])e[pp][4]=lim; if(e[pp][3]>e[pp][4])mark=1; e[pp][2]=e[pp][4]-e[pp][3]; suminf[n+col]+=e[pp][3]; sumouf[i]+=e[pp][3]; } else { e[nume][0]=n+col;e[nume][1]=head[i];head[i]=nume; e[nume][2]=0;e[nume][3]=lim;e[nume++][4]=lim; suminf[n+col]+=lim; sumouf[i]+=lim;hash[i][n+col]=1; e[nume][0]=i;e[nume][1]=head[n+col];head[n+col]=nume; e[nume++][2]=0; } } else if(cc=='>') { for(int i=1;i<=n;i++) { if(hash[i][n+col]) { int pp; for( pp=head[i];e[pp][0]!=n+col;pp=e[pp][1]) ; suminf[n+col]-=e[pp][3]; sumouf[i]-=e[pp][3]; if(lim+1>e[pp][3])e[pp][3]=lim+1; if(inf<e[pp][4])e[pp][4]=inf; if(e[pp][3]>e[pp][4])mark=1; e[pp][2]=e[pp][4]-e[pp][3]; suminf[n+col]+=e[pp][3]; sumouf[i]+=e[pp][3]; } else { e[nume][0]=n+col;e[nume][1]=head[i];head[i]=nume; e[nume][2]=inf-lim-1;e[nume][3]=lim+1;e[nume++][4]=inf; suminf[n+col]+=lim+1; sumouf[i]+=lim+1;hash[i][n+col]=1; e[nume][0]=i;e[nume][1]=head[n+col];head[n+col]=nume; e[nume++][2]=0; } } } else if(cc=='<') { for(int i=1;i<=n;i++) if(hash[i][n+col]) { int pp; for(pp=head[i];e[pp][0]!=n+col;pp=e[pp][1]) ; suminf[n+col]-=e[pp][3]; sumouf[i]-=e[pp][3]; if(0>e[pp][3])e[pp][3]=0; if(lim-1<e[pp][4])e[pp][4]=lim-1; if(e[pp][3]>e[pp][4])mark=1; e[pp][2]=e[pp][4]-e[pp][3]; suminf[n+col]+=e[pp][3]; sumouf[i]+=e[pp][3]; } else { e[nume][0]=n+col;e[nume][1]=head[i];head[i]=nume; e[nume][2]=lim-1;e[nume][3]=0;e[nume++][4]=lim-1;hash[i][n+col]=1; //inf[n+rol]+=lim; sumouf[i]+=lim; e[nume][0]=i;e[nume][1]=head[n+col];head[n+col]=nume; e[nume++][2]=0; } } } else if(row!=0&&col==0) { if(cc=='>') { for(int i=n+1;i<=n+m;i++) { if(hash[row][i]) { int pp; for( pp=head[row];e[pp][0]!=i;pp=e[pp][1]) ; suminf[i]-=e[pp][3]; sumouf[row]-=e[pp][3]; if(lim+1>e[pp][3])e[pp][3]=lim+1; if(inf<e[pp][4])e[pp][4]=inf; if(e[pp][3]>e[pp][4])mark=1; e[pp][2]=e[pp][4]-e[pp][3]; suminf[i]+=e[pp][3]; sumouf[row]+=e[pp][3]; } else { e[nume][0]=i;e[nume][1]=head[row];head[row]=nume; e[nume][2]=inf-lim-1;e[nume][3]=lim+1;e[nume++][4]=inf; suminf[i]+=lim+1; sumouf[row]+=lim+1;hash[row][i]=1; e[nume][0]=row;e[nume][1]=head[i];head[i]=nume; e[nume++][2]=0; } } } else if(cc=='=') for(int i=n+1;i<=n+m;i++) { if(hash[row][i]) { int pp; for(pp=head[row];e[pp][0]!=i;pp=e[pp][1]) ; suminf[i]-=e[pp][3]; sumouf[row]-=e[pp][3]; if(lim>e[pp][3])e[pp][3]=lim; if(lim<e[pp][4])e[pp][4]=lim; if(e[pp][3]>e[pp][4])mark=1; e[pp][2]=e[pp][4]-e[pp][3]; suminf[i]+=e[pp][3]; sumouf[row]+=e[pp][3]; } else { e[nume][0]=i;e[nume][1]=head[row];head[row]=nume; e[nume][2]=0;e[nume][3]=lim;e[nume++][4]=lim; suminf[i]+=lim; sumouf[row]+=lim;hash[row][i]=1; e[nume][0]=row;e[nume][1]=head[i];head[i]=nume; e[nume++][2]=0; } } else if(cc=='<') for(int i=n+1;i<=n+m;i++) { if(hash[row][i]) { int pp; for( pp=head[row];e[pp][0]!=i;pp=e[pp][1]) ; suminf[i]-=e[pp][3]; sumouf[row]-=e[pp][3]; if(0>e[pp][3])e[pp][3]=0; if(lim-1<e[pp][4])e[pp][4]=lim-1; if(e[pp][3]>e[pp][4])mark=1; e[pp][2]=e[pp][4]-e[pp][3]; suminf[i]+=e[pp][3]; sumouf[row]+=e[pp][3]; } else { e[nume][0]=i;e[nume][1]=head[row];head[row]=nume; e[nume][2]=lim-1;e[nume][3]=0;e[nume++][4]=lim-1;hash[row][i]=1; //inf[i]+=lim; sumouf[row]+=lim; e[nume][0]=row;e[nume][1]=head[i];head[i]=nume; e[nume++][2]=0; } } } else if(row==0&&col==0) { if(cc=='=') { for(int i=1;i<=n;i++) for(int j=n+1;j<=n+m;j++) { if(hash[i][j]) { int pp; for( pp=head[i];e[pp][0]!=j;pp=e[pp][1]) ; suminf[j]-=e[pp][3]; sumouf[i]-=e[pp][3]; if(lim>e[pp][3])e[pp][3]=lim; if(lim<e[pp][4])e[pp][4]=lim; if(e[pp][3]>e[pp][4])mark=1; e[pp][2]=e[pp][4]-e[pp][3]; suminf[j]+=e[pp][3]; sumouf[i]+=e[pp][3]; } else { e[nume][0]=j;e[nume][1]=head[i];head[i]=nume; e[nume][2]=0;e[nume][3]=lim;e[nume++][4]=lim; suminf[j]+=lim; sumouf[i]+=lim;hash[i][j]=1; e[nume][0]=i;e[nume][1]=head[j];head[j]=nume; e[nume++][2]=0; } } } if(cc=='>') { for(int i=1;i<=n;i++) for(int j=n+1;j<=n+m;j++) { if(hash[i][j]) { int pp; for( pp=head[i];e[pp][0]!=j;pp=e[pp][1]) ; suminf[j]-=e[pp][3]; sumouf[i]-=e[pp][3]; if(lim+1>e[pp][3])e[pp][3]=lim+1; if(inf<e[pp][4])e[pp][4]=inf; if(e[pp][3]>e[pp][4])mark=1; e[pp][2]=e[pp][4]-e[pp][3]; suminf[j]+=e[pp][3]; sumouf[i]+=e[pp][3]; } else { e[nume][0]=j;e[nume][1]=head[i];head[i]=nume; e[nume][2]=inf-lim-1;e[nume][3]=lim+1;e[nume++][4]=inf; suminf[j]+=lim+1; sumouf[i]+=lim+1;hash[i][j]=1; e[nume][0]=i;e[nume][1]=head[j];head[j]=nume; e[nume++][2]=0; } } } if(cc=='<') for(int i=1;i<=n;i++) for(int j=n+1;j<=n+m;j++) { if(hash[i][j]) { int pp; for( pp=head[i];e[pp][0]!=j;pp=e[pp][1]) ; suminf[j]-=e[pp][3]; sumouf[i]-=e[pp][3]; if(0>e[pp][3])e[pp][3]=0; if(lim-1<e[pp][4])e[pp][4]=lim-1; if(e[pp][3]>e[pp][4])mark=1; e[pp][2]=e[pp][4]-e[pp][3]; suminf[j]+=e[pp][3]; sumouf[i]+=e[pp][3]; } else { e[nume][0]=j;e[nume][1]=head[i];head[i]=nume; e[nume][2]=lim-1;e[nume][3]=0;e[nume++][4]=lim-1;hash[i][j]=1; //inf[j]+=lim; sumouf[i]+=lim; e[nume][0]=i;e[nume][1]=head[j];head[j]=nume; e[nume++][2]=0; } } } else { if(cc=='=') { if(hash[row][n+col]) { int pp; for(pp=head[row];e[pp][0]!=n+col;pp=e[pp][1]) ; suminf[n+col]-=e[pp][3]; sumouf[row]-=e[pp][3]; if(lim>e[pp][3])e[pp][3]=lim; if(lim<e[pp][4])e[pp][4]=lim; if(e[pp][3]>e[pp][4])mark=1; e[pp][2]=e[pp][4]-e[pp][3]; suminf[n+col]+=e[pp][3]; sumouf[row]+=e[pp][3]; } else { e[nume][0]=col+n;e[nume][1]=head[row];head[row]=nume; e[nume][2]=0;e[nume][3]=lim;e[nume++][4]=lim; suminf[col+n]+=lim; sumouf[row]+=lim;hash[row][col+n]=1; e[nume][0]=row;e[nume][1]=head[col+n];head[col+n]=nume; e[nume++][2]=0; } } else if(cc=='>') { if(hash[row][n+col]) { int pp; for(pp=head[row];e[pp][0]!=n+col;pp=e[pp][1]) ; suminf[n+col]-=e[pp][3]; sumouf[row]-=e[pp][3]; if(lim+1>e[pp][3])e[pp][3]=lim+1; if(inf<e[pp][4])e[pp][4]=inf; if(e[pp][3]>e[pp][4])mark=1; e[pp][2]=e[pp][4]-e[pp][3]; suminf[n+col]+=e[pp][3]; sumouf[row]+=e[pp][3]; } else { e[nume][0]=col+n;e[nume][1]=head[row];head[row]=nume; e[nume][2]=inf-lim-1;e[nume][3]=lim+1;e[nume++][4]=inf; suminf[col+n]+=lim+1; sumouf[row]+=lim+1;hash[row][col+n]=1; e[nume][0]=row;e[nume][1]=head[col+n];head[col+n]=nume; e[nume++][2]=0; } } else if(cc=='<') { if(hash[row][n+col]) { int pp; for( pp=head[row];e[pp][0]!=n+col;pp=e[pp][1]) ; suminf[n+col]-=e[pp][3]; sumouf[row]-=e[pp][3]; if(0>e[pp][3])e[pp][3]=0; if(lim-1<e[pp][4])e[pp][4]=lim-1; if(e[pp][3]>e[pp][4])mark=1; e[pp][2]=e[pp][4]-e[pp][3]; suminf[n+col]+=e[pp][3]; sumouf[row]+=e[pp][3]; } else { e[nume][0]=col+n;e[nume][1]=head[row];head[row]=nume; e[nume][2]=lim-1;e[nume][3]=0;e[nume++][4]=lim-1;hash[row][col+n]=1; // inf[col]+=lim; sumouf[row]+=lim; e[nume][0]=row;e[nume][1]=head[col+n];head[col+n]=nume; e[nume++][2]=0; } } } } for(int i=1;i<=n;i++) //有些边没有限制,不要忘记加边!! for(int j=n+1;j<=n+m;j++) if(!hash[i][j]) { e[nume][0]=j;e[nume][1]=head[i];head[i]=nume; e[nume][4]=inf;e[nume++][2]=inf; e[nume][0]=i;e[nume][1]=head[j];head[j]=nume; e[nume++][2]=0; } //无源无汇添加ss,tt for(int i=0;i<=n+m+1;i++) { e[nume][0]=i;e[nume][1]=head[n+m+2];head[n+m+2]=nume; e[nume++][2]=suminf[i]; e[nume][0]=n+m+2;e[nume][1]=head[i];head[i]=nume; e[nume++][2]=0; e[nume][0]=n+m+3;e[nume][1]=head[i];head[i]=nume; e[nume++][2]=sumouf[i]; e[nume][0]=i;e[nume][1]=head[n+m+3];head[n+m+3]=nume; e[nume++][2]=0; } dinic(); //从ss->tt,判断有无解 if(mark||!check())printf("IMPOSSIBLE "); else //输出答案 { for(int i=1;i<=n;i++) for(int j=head[i];j!=-1;j=e[j][1]) ans[i][e[j][0]]=e[j][4]-e[j][2]; //原来上限-残留量,即为所用(上限-下限-残留+下限) for(int i=1;i<=n;i++) for(int j=n+1;j<=n+m;j++) { if(j!=n+m)printf("%d ",ans[i][j]); else printf("%d ",ans[i][j]); } } if(N!=0)printf(" "); } return 0; }