poj 2396 Budget
一个m行n列的矩阵,给出每行每列中元素的和,以及对一些格子的大小限制,求一个可行方案,输出矩阵。
大小限制形如:严格大于i,严格小于i,等于i。
1<=m<=200.1<=n<=20.
有源汇上下界可行流。
将每一行作为一个点,每一列作为一个点。
源点向每个行点连一条上下界均为该行和的边。
每个列点向汇点连一条上下界均为该列和的边。
每个行点向各列点连一条上下界为该行该列对应点的上下限的边。
然后做一遍有源汇上下界可行流就好了。
(汇点向源点连一条上界为正无穷下界为0的边,就转成无源汇上下界可行流啦!
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 const int dian=305; 8 const int bian=10005; 9 const int INF=0x3f3f3f3f; 10 int h[dian],nxt[bian],ver[bian],val[bian],ch[dian],cr[dian]; 11 int sx[205][25],xx[205][25],bh[205][25],in[dian],out[dian]; 12 int n,m,aa,bb,cc,tot,num,flag,summ; 13 int S,T,SS,TT; 14 char la[10]; 15 void add(int a,int b,int c,int d){ 16 tot++;ver[tot]=b;val[tot]=d-c;nxt[tot]=h[a];h[a]=tot; 17 tot++;ver[tot]=a;val[tot]=0;nxt[tot]=h[b];h[b]=tot; 18 in[b]+=c; 19 out[a]+=c; 20 } 21 bool tell(){ 22 memset(ch,-1,sizeof(ch)); 23 queue<int>q; 24 q.push(S); 25 ch[S]=0; 26 while(!q.empty()){ 27 int t=q.front(); 28 q.pop(); 29 for(int i=h[t];i;i=nxt[i]) 30 if(ch[ver[i]]==-1&&val[i]){ 31 ch[ver[i]]=ch[t]+1; 32 q.push(ver[i]); 33 } 34 } 35 return ch[T]!=-1; 36 } 37 int zeng(int a,int b){ 38 if(a==T) 39 return b; 40 int r=0; 41 for(int i=cr[a];i&&b>r;i=nxt[i]) 42 if(ch[ver[i]]==ch[a]+1&&val[i]){ 43 int t=zeng(ver[i],min(b-r,val[i])); 44 val[i]-=t,r+=t,val[i^1]+=t; 45 if(val[i]) 46 cr[a]=i; 47 } 48 if(!r) 49 ch[a]=-1; 50 return r; 51 } 52 int dinic(){ 53 int r=0,t; 54 while(tell()){ 55 for(int i=1;i<=n+m+4;i++) 56 cr[i]=h[i]; 57 while(t=zeng(S,INF)) 58 r+=t; 59 } 60 return r; 61 } 62 int main(){ 63 int cas; 64 scanf("%d",&cas); 65 while(cas--){ 66 memset(h,0,sizeof(h)); 67 memset(nxt,0,sizeof(nxt)); 68 memset(sx,0x3f,sizeof(sx)); 69 memset(xx,0,sizeof(xx)); 70 memset(in,0,sizeof(in)); 71 memset(out,0,sizeof(out)); 72 tot=1; 73 summ=0; 74 scanf("%d%d",&n,&m); 75 SS=n+m+1,TT=n+m+2,S=n+m+3,T=n+m+4; 76 for(int i=1;i<=n;i++){ 77 scanf("%d",&aa); 78 add(SS,i,aa,aa); 79 } 80 for(int i=1;i<=m;i++){ 81 scanf("%d",&aa); 82 add(n+i,TT,aa,aa); 83 } 84 scanf("%d",&num); 85 while(num--){ 86 scanf("%d%d%s%d",&aa,&bb,la,&cc); 87 if(!aa&&!bb){ 88 for(int i=1;i<=n;i++) 89 for(int j=1;j<=m;j++){ 90 if(la[0]=='<') 91 sx[i][j]=min(sx[i][j],cc-1); 92 else if(la[0]=='>') 93 xx[i][j]=max(xx[i][j],cc+1); 94 else{ 95 sx[i][j]=min(sx[i][j],cc); 96 xx[i][j]=max(xx[i][j],cc); 97 } 98 } 99 } 100 else if(!aa){ 101 for(int i=1;i<=n;i++){ 102 if(la[0]=='<') 103 sx[i][bb]=min(sx[i][bb],cc-1); 104 else if(la[0]=='>') 105 xx[i][bb]=max(xx[i][bb],cc+1); 106 else{ 107 sx[i][bb]=min(sx[i][bb],cc); 108 xx[i][bb]=max(xx[i][bb],cc); 109 } 110 } 111 } 112 else if(!bb){ 113 for(int i=1;i<=m;i++){ 114 if(la[0]=='<') 115 sx[aa][i]=min(sx[aa][i],cc-1); 116 else if(la[0]=='>') 117 xx[aa][i]=max(xx[aa][i],cc+1); 118 else{ 119 sx[aa][i]=min(sx[aa][i],cc); 120 xx[aa][i]=max(xx[aa][i],cc); 121 } 122 } 123 for(int i=1;i<=n;i++){ 124 if(la[0]=='<') 125 sx[i][bb]=min(sx[i][bb],cc-1); 126 else if(la[0]=='>') 127 xx[i][bb]=max(xx[i][bb],cc+1); 128 else{ 129 sx[i][bb]=min(sx[i][bb],cc); 130 xx[i][bb]=max(xx[i][bb],cc); 131 } 132 } 133 } 134 else{ 135 if(la[0]=='<') 136 sx[aa][bb]=min(sx[aa][bb],cc-1); 137 else if(la[0]=='>') 138 xx[aa][bb]=max(xx[aa][bb],cc+1); 139 else{ 140 sx[aa][bb]=min(sx[aa][bb],cc); 141 xx[aa][bb]=max(xx[aa][bb],cc); 142 } 143 } 144 } 145 flag=0; 146 for(int i=1;i<=n;i++){ 147 for(int j=1;j<=m;j++){ 148 if(sx[i][j]>=xx[i][j]){ 149 bh[i][j]=tot+1; 150 add(i,n+j,xx[i][j],sx[i][j]); 151 } 152 else{ 153 flag=1; 154 break; 155 } 156 } 157 if(flag) 158 break; 159 } 160 if(flag){ 161 puts("IMPOSSIBLE"); 162 puts(""); 163 continue; 164 } 165 add(TT,SS,0,INF); 166 for(int i=1;i<=TT;i++){ 167 if(in[i]-out[i]>0) 168 add(S,i,0,in[i]-out[i]); 169 else if(out[i]-in[i]>0){ 170 add(i,T,0,out[i]-in[i]); 171 summ=summ+out[i]-in[i]; 172 } 173 } 174 if(dinic()!=summ){ 175 puts("IMPOSSIBLE"); 176 puts(""); 177 continue; 178 } 179 for(int i=1;i<=n;i++){ 180 for(int j=1;j<=m;j++) 181 printf("%d ",xx[i][j]+val[bh[i][j]^1]); 182 puts(""); 183 } 184 puts(""); 185 } 186 return 0; 187 }
注意:
一个格子可能有多重限制,上限取min下限取max。
上限可能小于下限要判掉。
每组数据输出间有空行(不加也没事?)。
如果wa了就再读一遍建图,不行就再读一遍。