POJ 2396 Budget (上下界网络流有源可行流)

转载: http://blog.csdn.net/axuan_k/article/details/47297395

题目描述:

现在要针对多赛区竞赛制定一个预算,该预算是一个行代表不同种类支出、列代表不同赛区支出的矩阵。组委会曾经开会讨论过各类支出的总和,以及各赛区所需支出的总和。

另外,组委会还讨论了一些特殊的约束条件:例如,有人提出计算机中心至少需要1000K 里亚尔(伊朗货币),用于购买食物;也有人提出Sharif 赛区用于购买体恤衫的费用不能超过30000K 里亚尔。

组委会的任务是制定一个满足所有约束条件且行列和满足要求的预算。

解题报告:

该题解题关键在于建图, 将行置于左边,列置于右边,然后连接所有行和列,每条边表示第x行第y列的物品的价格预算。

根据约束条件来限定这些边的上界与下界,从而将题目转化为 有上下界的可行流求解:

已有边的权为c[i][j]-b[i][j]      

另外构造源点和汇点    分别连接 所有行 和 所有列  

边权为 sum[x]-sum(b[x][i])        sum[y]-sum(b[i][y])

如果源流和汇流相等 则说明有可行解

相当于无源,我们只需汇点向源点连一条[0,inf]的边就行了

  1 #include <iostream>  
  2 #include <cstring>  
  3 #include <cstdio>  
  4 #include <algorithm>  
  5 #include <queue>  
  6 const int MAXN =505;  
  7 const int MAXM=440020;  
  8 const int INF=0x3f3f3f;  
  9 const int maxx=0x3f3f3f3f;  
 10 using namespace std;  
 11 struct Edge {  
 12     int to,cap,flow,next;  
 13 } edge[MAXM];  
 14 int head[MAXN],tot,gap[MAXN],d[MAXN],cur[MAXN],que[MAXN],p[MAXN];  
 15   
 16 void init()  
 17 {  
 18     tot=0;  
 19     memset(head,-1,sizeof(head));  
 20 }  
 21   
 22 int isap(int source,int sink,int N)  
 23 {  
 24     memset(gap,0,sizeof(gap));  
 25     memset(d,0,sizeof(d));  
 26     memcpy(cur,head,sizeof(head));  
 27     int top = 0,x = source,flow = 0;  
 28     while(d[source] < N) {  
 29         if(x == sink) {  
 30             int Min = maxx,inser=0;  
 31             for(int i = 0; i < top; ++i) {  
 32                 if(Min > edge[p[i]].cap - edge[p[i]].flow) {  
 33                     Min = edge[p[i]].cap - edge[p[i]].flow;  
 34                     inser = i;  
 35                 }  
 36             }  
 37             for(int i = 0; i < top; ++i) {  
 38                 edge[p[i]].flow += Min;  
 39                 edge[p[i]^1].flow -= Min;  
 40             }  
 41             if(Min!=INF) flow += Min;  
 42             top = inser;  
 43             x = edge[p[top]^1].to;  
 44             continue;  
 45         }  
 46         int ok = 0;  
 47         for(int i = cur[x]; i != -1; i = edge[i].next) {  
 48             int v = edge[i].to;  
 49             if(edge[i].cap > edge[i].flow && d[v]+1 == d[x]) {  
 50                 ok = 1;  
 51                 cur[x] = i;  
 52                 p[top++] = i;  
 53                 x = edge[i].to;  
 54                 break;  
 55             }  
 56         }  
 57         if(!ok) {  
 58             int Min = N;  
 59             for(int i = head[x]; i != -1; i = edge[i].next) {  
 60                 if(edge[i].cap > edge[i].flow && d[edge[i].to] < Min) {  
 61                     Min = d[edge[i].to];  
 62                     cur[x] = i;  
 63                 }  
 64             }  
 65             if(--gap[d[x]] == 0) break;  
 66             gap[d[x] = Min+1]++;  
 67             if(x != source) x = edge[p[--top]^1].to;  
 68         }  
 69     }  
 70     return flow;  
 71 }  
 72   
 73 int b[205][25],h[205][25];  
 74 int sumr[205],sumc[205];  
 75 int id[205][25];      //用来保存[i][j]在邻接表的边的编号  
 76 int s,t;  
 77 int n,m;  
 78 int sum;  
 79 int flag;  
 80   
 81 void addedge(int u,int v,int c,int x,int y)  
 82 {  
 83     edge[tot]=(Edge){v,c,0,head[u]};  
 84     id[x][y]= head[u] = tot++;  
 85     edge[tot]=(Edge){u,c,c,head[v]};  
 86     head[v] = tot++;  
 87 }  
 88   
 89 void set_(int x,int y,char ch,int v)  
 90 {  
 91     if(ch=='=')  
 92     {  
 93         if(b[x][y]>v)  
 94             flag=1;  
 95         if(h[x][y]<v)  
 96             flag=1;  
 97         b[x][y]=h[x][y]=v;  
 98     }  
 99     else if(ch=='>')  
100     {  
101         if(h[x][y]<=v)  
102             flag=1;  
103         b[x][y]=max(b[x][y],v+1);  
104     }  
105     else  
106     {  
107         if(b[x][y]>=v)  
108             flag=1;  
109         h[x][y]=min(h[x][y],v-1);  
110     }  
111 }  
112   
113 void build()  
114 {  
115     for(int i=1;i<=n;i++)  
116         for(int j=1;j<=m;j++)  
117             addedge(i,n+j,h[i][j]-b[i][j],i,j);  
118     for(int i=1;i<=n+m;i++)  
119     {  
120         int f=i<=n?sumr[i]:-sumc[i-n];  
121         if(i<=n)  
122             for(int j=1;j<=m;j++)  
123                 f-=b[i][j];  
124         else  
125             for(int j=1;j<=n;j++)  
126                 f+=b[j][i-n];  
127         if(f>0){  
128             addedge(s,i,f,0,0);  
129             sum+=f;  
130         }  
131         else  
132             addedge(i,t,-f,0,0);  
133     }  
134 }  
135   
136 int main()  
137 {  
138 //    freopen("in.txt","r",stdin);  
139     int T;  
140     int nn,a,bb,c;  
141     char ch;  
142     scanf("%d",&T);  
143     for(int Case=1;Case<=T;Case++)  
144     {  
145         if(Case!=1)  
146             printf("
");  
147         scanf("%d%d",&n,&m);  
148         init();  
149         s=0,t=n+m+1;  
150         sum=0;  
151         flag=0;  
152   
153         for(int i=1;i<=n;i++)  
154             for(int j=1;j<=m;j++)  //初始上下界  
155             {  
156                 b[i][j]=0;  
157                 h[i][j]=INF;  
158             }  
159         for(int i=1;i<=n;i++)  
160             scanf("%d",&sumr[i]);  
161         for(int j=1;j<=m;j++)  
162             scanf("%d",&sumc[j]);  
163         scanf("%d",&nn);  
164         while(nn--)    //限定上下界  
165         {  
166             cin>>a>>bb>>ch>>c;  
167             if(!a&&!bb)  
168             {  
169                 for(int i=1;i<=n;i++)  
170                     for(int j=1;j<=m;j++)  
171                         set_(i,j,ch,c);  
172             }  
173             else if(!a&&bb)  
174             {  
175                 for(int i=1;i<=n;i++)  
176                     set_(i,bb,ch,c);  
177             }  
178             else if(a&&!bb)  
179             {  
180                 for(int i=1;i<=m;i++)  
181                     set_(a,i,ch,c);  
182             }  
183             else  
184                 set_(a,bb,ch,c);  
185         }  
186         if(flag==1){    //约束条件矛盾  
187             printf("IMPOSSIBLE
");  
188             continue;  
189         }  
190         build();  
191         int ans=isap(s,t,t+1);  
192   
193         if(sum!=ans)        //源流==汇流  
194             printf("IMPOSSIBLE
");  
195         else {  
196             for(int i=1;i<=n;i++)  
197                 for(int j=1;j<=m;j++)  
198                     if(j==m)  
199                         printf("%d
",b[i][j]+edge[id[i][j]].flow);  
200                     else  
201                         printf("%d ",b[i][j]+edge[id[i][j]].flow);  
202         }  
203     }  
204     return 0;  
205 }  
原文地址:https://www.cnblogs.com/agenthtb/p/7678865.html