【POJ 2396 Budget】 有上下界的可行流
题目链接:http://poj.org/problem?id=2396
题目大意:有一个n*m的矩阵,每个位置(i,j)都有一个值,接下来输入n个数,每个数代表矩阵对应行的和,接下来输入m个数,每个数代表对应列的和。接下来有Q个操作,每个操作输入i j c val。(注意i==0||j==0的特判。这里不说明了)
1、当c为'>': 表示第i行j列的数值要大于val。(实际下级要设为val+1)
2、当c为'<': 表示第i行j列的数值要小于val。(实际上界要设为val-1)
3、当c为'=': 表示第i行j列的数值要等于val。
让你求是否存在满足要求的矩阵,有则输出对应的矩阵,无则输出”impossible”。
解题思路:其实这样的题吧,关键还是想到构图,想到了就是一水,没想到就是一难。
增设一源点s和一汇点d,源点s和每行的代表虚拟节点row[i]相连,权值为该行的权值总和,每列的代表虚拟节点和汇点d相连,权值为该列的权值总和,行连接列代表节点(i,j)即i行j列,它的容量上下界根据题目来确定。
连接一条附加边(d,s)容量为无穷,剩下的操作和无源汇有上下界的可行流一样。
这题让我蛋疼了许久,让我又悲又喜,悲的是明显各种测试各种对就是TLE(最后我还猥琐的去官方下载数据),喜的是这题让我找到了我的Dinic模板的一个bug,就是这个bug才让我的Dinic跑慢了许多,唉,前面写了那么多题都没测试出来,弱爆了。
View Code
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <algorithm> 6 using namespace std; 7 8 const int mn=5555; 9 const int mm=100000; 10 const int oo=0x3fffffff; 11 int node, st, sd, edge; 12 int reach[mm], flow[mm], next[mm]; 13 int head[mn], work[mn], dis[mn], que[mn]; 14 int low[225][225], up[225][225], du[mn], ans[225][225]; 15 bool flag; 16 17 inline void init(int _node, int _st, int _sd) 18 { 19 node=_node, st=_st, sd=_sd; 20 for(int i=0; i<node; i++) 21 head[i]=-1, du[i]=0; 22 edge=0; 23 } 24 25 void addedge(int u, int v, int c1, int c2) 26 { 27 reach[edge]=v, flow[edge]=c1, next[edge]=head[u], head[u]=edge++; 28 reach[edge]=u, flow[edge]=c2, next[edge]=head[v], head[v]=edge++; 29 } 30 31 bool bfs() 32 { 33 int u, v, l=0, h=0; 34 for(int i=0; i<node; i++) dis[i]=-1; 35 dis[st]=0; 36 que[l++]=st; 37 while(l!=h) 38 { 39 u=que[h++]; 40 if(h==mn) h=0; 41 for(int i=head[u]; i>=0; i=next[i]) 42 { 43 v=reach[i]; 44 if(flow[i]>0&&dis[v]<0) ///!!题目中可能边权有为负的边,TLE到死 45 { 46 dis[v]=dis[u]+1; 47 que[l++]=v; 48 if(l==mn) l=0; 49 if(v==sd) return true; 50 } 51 } 52 } 53 return false; 54 } 55 56 int dfs(int u, int exp) 57 { 58 if(sd==u) return exp; 59 for(int &i=work[u]; i>=0; i=next[i]) 60 { 61 int v=reach[i], tmp; 62 if(flow[i]>0&&dis[v]==dis[u]+1&&(tmp=dfs(v,min(flow[i],exp)))>0) 63 { 64 flow[i]-=tmp; 65 flow[i^1]+=tmp; 66 return tmp; 67 } 68 } 69 return 0; 70 } 71 72 int Dinic() 73 { 74 int max_flow=0, flow; 75 while(bfs()) 76 { 77 for(int i=0; i<node; i++) work[i]=head[i]; 78 while(flow=dfs(st,oo)) max_flow+=flow; 79 } 80 return max_flow; 81 } 82 83 void change(int u, int v,int a, int b) 84 { 85 low[u][v]=max(low[u][v],a); 86 up[u][v]=min(up[u][v],b); 87 if(low[u][v]>up[u][v]) flag=1; 88 } 89 90 int main() 91 { 92 int g, n, m, T, Q, tcase=0; 93 cin >> T; 94 while(T--) 95 { 96 int aa=0, bb=0; 97 scanf("%d%d",&n,&m); 98 init(n+m+2,0,n+m+1); 99 for(int i=1; i<=n; i++) 100 { 101 scanf("%d",&g); 102 aa+=g; 103 du[st]-=g; 104 du[i]+=g; 105 } 106 for(int i=1; i<=m; i++) 107 { 108 scanf("%d",&g); 109 bb+=g; 110 du[i+n]-=g; 111 du[sd]+=g; 112 } 113 for(int i=1; i<225; i++) 114 for(int j=1; j<225; j++) 115 { 116 low[i][j]=0; 117 up[i][j]=oo; 118 } 119 cin >> Q; 120 int u, v, c, flag=0; 121 char ch[5]; 122 while(Q--) 123 { 124 scanf("%d%d%s%d",&u,&v,ch,&c); 125 if(u==0&&v==0) 126 { 127 for(int i=1; i<=n; i++) 128 for(int j=1; j<=m; j++) 129 { 130 if(ch[0]=='>') change(i,j+n,c+1,up[i][j+n]); 131 else if(ch[0]=='<') change(i,j+n,low[i][j+n],c-1); 132 else change(i,j+n,c,c); 133 } 134 } 135 else if(u==0) 136 { 137 for(int i=1; i<=n; i++) 138 { 139 if(ch[0]=='>') change(i,v+n,c+1,up[i][v+n]); 140 else if(ch[0]=='<') change(i,v+n,low[i][v+n],c-1); 141 else change(i,v+n,c,c); 142 } 143 } 144 else if(v==0) 145 { 146 for(int j=1; j<=m; j++) 147 { 148 if(ch[0]=='>') change(u,j+n,c+1,up[u][j+n]); 149 else if(ch[0]=='<') change(u,j+n,low[u][j+n],c-1); 150 else change(u,j+n,c,c); 151 } 152 } 153 else 154 { 155 if(ch[0]=='>') change(u,v+n,c+1,up[u][v+n]); 156 else if(ch[0]=='<') change(u,v+n,low[u][v+n],c-1); 157 else change(u,v+n,c,c); 158 } 159 } 160 if(tcase) puts(""); 161 tcase=1; 162 if(flag||aa!=bb) puts("IMPOSSIBLE"); 163 else 164 { 165 addedge(sd,st,oo,0); 166 for(int i=1; i<=n; i++) 167 for(int j=1; j<=m; j++) 168 { 169 du[i]-=low[i][j+n]; 170 du[j+n]+=low[i][j+n]; 171 addedge(i,j+n,up[i][j+n]-low[i][j+n],0); 172 } 173 st=node, sd=node+1, node+=2; 174 head[st]=head[sd]=-1; 175 int flowmax, sum=0; 176 for(int i=0; i<node-2; i++) 177 { 178 if(du[i]>0) sum+=du[i], addedge(st,i,du[i],0); 179 if(du[i]<0) addedge(i,sd,-du[i],0); 180 } 181 flowmax=Dinic(); 182 if(flowmax!=sum) puts("IMPOSSIBLE"); 183 else 184 { 185 for(int i=1; i<=n; i++) 186 for(int j=head[i]; j>=0; j=next[j]) 187 ans[i][reach[j]]=flow[j^1]+low[i][reach[j]]; 188 for(int i=1; i<=n; i++) 189 for(int j=1; j<=m; j++) 190 { 191 if(j!=m) printf("%d ",ans[i][j+n]); 192 else printf("%d\n",ans[i][j+n]); 193 } 194 } 195 } 196 } 197 return 0; 198 }