@ivorysi
2018-03-29T13:22:25.000000Z
字数 24755
阅读 793
笔记
The terrorist group leaded by a well known international terrorist Ben Bladen is buliding a nuclear reactor to produce plutonium for the nuclear bomb they are planning to create. Being the wicked computer genius of this group, you are responsible for developing the cooling system for the reactor.
The cooling system of the reactor consists of the number of pipes that special cooling liquid flows by. Pipes are connected at special points, called nodes, each pipe has the starting node and the end point. The liquid must flow by the pipe from its start point to its end point and not in the opposite direction.
Let the nodes be numbered from 1 to N. The cooling system must be designed so that the liquid is circulating by the pipes and the amount of the liquid coming to each node (in the unit of time) is equal to the amount of liquid leaving the node. That is, if we designate the amount of liquid going by the pipe from i-th node to j-th as fij, (put fij = 0 if there is no pipe from node i to node j), for each i the following condition must hold:
fi,1+fi,2+...+fi,N = f1,i+f2,i+...+fN,i
Each pipe has some finite capacity, therefore for each i and j connected by the pipe must be fij <= cij where cij is the capacity of the pipe. To provide sufficient cooling, the amount of the liquid flowing by the pipe going from i-th to j-th nodes must be at least lij, thus it must be fij >= lij.
Given cij and lij for all pipes, find the amount fij, satisfying the conditions specified above.
This problem contains multiple test cases!
The first line of a multiple input is an integer N, then a blank line followed by N input blocks. Each input block is in the format indicated in the problem description. There is a blank line between input blocks.
The output format consists of N output blocks. There is a blank line between output blocks.
The first line of the input file contains the number N (1 <= N <= 200) - the number of nodes and and M - the number of pipes. The following M lines contain four integer number each - i, j, lij and cij each. There is at most one pipe connecting any two nodes and 0 <= lij <= cij <= 10^5 for all pipes. No pipe connects a node to itself. If there is a pipe from i-th node to j-th, there is no pipe from j-th node to i-th.
On the first line of the output file print YES if there is the way to carry out reactor cooling and NO if there is none. In the first case M integers must follow, k-th number being the amount of liquid flowing by the k-th pipe. Pipes are numbered as they are given in the input file.
2
4 6
1 2 1 2
2 3 1 2
3 4 1 2
4 1 1 2
1 3 1 2
4 2 1 24 6
1 2 1 3
2 3 1 3
3 4 1 3
4 1 1 3
1 3 1 3
4 2 1 3
NO
YES
1
2
3
2
1
1
这里的水是循环流动的
我们考虑网络流,需要满足一个流量平衡条件,就像题里说的
对于任意一点i,设每条边经过的流量为,都有
也就是所说的流量平衡条件
然后由于每条边有一个上界,有一个下界,我们还要满足这个条件
我们设是新图边的流量
以为我们能在这个图上跑网络流了吗?so naive,不行
我们并不能满足下界
所以再去看这个流量平衡条件
我们设
新建一个源点和汇点
我们从源点连一条边到,容量为
我们从连一条边到汇点,容量为
我们再把每条边的容量改成上下界的差值,然后去跑一遍网络流,如果原点出发的任意一条弧,和到达汇点的任意一条弧都满流,那么就在原网络中对应一条可行流
最后检查一下到流量是否与源点出发的弧的容量总和相等即可
如果需要算出每条边的真实流量,就用流量下界,加上该边在新图中的流量即可
纠结了一会为什么源点满流代表到汇点的弧也满流,然后发现……每条边的下界被加一遍也被减一遍,所以当然从源点出发弧的容量总和等于到汇点的弧的容量总和
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define MAXN 205
//#define ivorysi
using namespace std;
typedef long long ll;
struct node {
int to,next,val;
}edge[100005];
int head[MAXN],sumedge;
int n,m,T;
int d[MAXN],dis[MAXN],gap[MAXN],low[100005],source,sink,tot;
void add(int u,int v,int c) {
edge[++sumedge].to=v;
edge[sumedge].next=head[u];
edge[sumedge].val=c;
head[u]=sumedge;
}
void addtwo(int u,int v,int c) {
add(u,v,c);add(v,u,0);
}
int sap(int u,int aug) {
if(u==sink) return aug;
int dmin=sink-1,flow=0;
for(int i=head[u];i;i=edge[i].next) {
if(edge[i].val>0) {
int v=edge[i].to;
if(dis[v]+1==dis[u]) {
int t=sap(v,min(aug-flow,edge[i].val));
flow+=t;
edge[i].val-=t;
edge[i^1].val+=t;
if(dis[source]>=sink) return flow;
if(flow==aug) return flow;
}
dmin=min(dmin,dis[v]);
}
}
if(!flow) {
--gap[dis[u]];
if(gap[dis[u]]==0) dis[source]=sink;
dis[u]=dmin+1;
++gap[dis[u]];
}
return flow;
}
void solve() {
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
memset(d,0,sizeof(d));
memset(head,0,sizeof(head));sumedge=1;
scanf("%d%d",&n,&m);
int u,v,c;
siji(i,1,m) {
scanf("%d%d%d%d",&u,&v,&low[i],&c);
addtwo(u,v,c-low[i]);
d[v]+=low[i];
d[u]-=low[i];
}
source=n+1,sink=n+2;
tot=0;
siji(i,1,n) {
if(d[i]>0) addtwo(source,i,d[i]),tot+=d[i];
else if(d[i]<0) addtwo(i,sink,-d[i]);
}
while(dis[source]<sink && tot) tot-=sap(source,tot);
if(tot!=0) {
puts("NO");
}
else {
puts("YES");
siji(i,1,m) {
printf("%d\n",low[i]+edge[2*i+1].val);
}
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
scanf("%d",&T);
int cnt=0;
while(T--) {
++cnt;
if(cnt!=1) puts("");
solve();
}
return 0;
}
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.
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 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.
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.
2
2 3
8 10
5 6 7
4
0 2 > 2
2 1 = 3
2 3 > 2
2 3 < 52 2
4 5
6 7
1
1 1 > 10
2 3 3
3 3 4IMPOSSIBLE
这道题思路比较明显当然是行列拆点,由于规定了行的和与列的和那么容易想到建一个源点连向每一行,每一列连向汇点,容量分别为各自的和,汇点再连到源点,由于源点和汇点都是流量平衡的,所以可以不用考虑他们,计算就考虑行列拆出的点即可
然后就是存图!!!只要我们能把行列的上下界记下来就万事大吉了……
注意我们要去众多上界中最小的上界,众多下界中最大的下界,如果是=号打个标记,下次修改的时候记录一下值的可取区间,如果这个之前固定好的容量不在这个可取区间里,那就不合法,注意如果在读判断条件的时候找到不合法了,把后面的东西读完再跳出
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
//#define ivorysi
using namespace std;
typedef long long ll;
struct node {
int to,next,val;
}edge[2000005];
int sumedge,head[405];
void add(int u,int v,int c) {
edge[++sumedge].to=v;
edge[sumedge].next=head[u];
edge[sumedge].val=c;
head[u]=sumedge;
}
void addtwo(int u,int v,int c) {
add(u,v,c);add(v,u,0);
}
int low[205][205],upp[205][205],r,c,op,d[405],tot,source,sink;
bool disable[205][205];
int dis[405],gap[405];
int sap(int u,int aug) {
if(u==sink) return aug;
int dmin=sink-1,flow=0;
for(int i=head[u];i;i=edge[i].next) {
if(edge[i].val>0) {
int v=edge[i].to;
if(dis[v]+1==dis[u]) {
int t=sap(v,min(edge[i].val,aug-flow));
flow+=t;
edge[i].val-=t;
edge[i^1].val+=t;
if(flow==aug) return flow;
if(dis[source]>=sink) return flow;
}
dmin=min(dmin,dis[v]);
}
}
if(!flow) {
--gap[dis[u]];
if(gap[dis[u]]==0) dis[source]=sink;
dis[u]=dmin+1;
++gap[dis[u]];
}
return flow;
}
void solve() {
memset(head,0,sizeof(head));sumedge=1;
memset(low,0,sizeof(low));
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
memset(d,0,sizeof(d));
memset(disable,0,sizeof(disable));
scanf("%d%d",&r,&c);
int x,y,v;
char s[10];
tot=0;
siji(i,1,r) {
scanf("%d",&x);
tot+=x;
d[i]+=x;
}
siji(i,1,c) {
scanf("%d",&x);
tot-=x;
d[i+r]-=x;
}
siji(i,1,r) {
siji(j,1,c) {
upp[i][j]=0x7fffffff;
}
}
scanf("%d",&op);
int a,b;
siji(i,1,op) {
scanf("%d%d%s%d",&x,&y,s,&v);
if(s[0]=='<') {v--;b=v;a=0;}
else if(s[0]=='>') {++v;a=v;b=0x7fffffff;}
else a=b=v;
if(x==0 &&y==0) {
siji(j,1,r) {
siji(k,1,c) {
if(disable[j][k] && (!(low[j][k]<=b && low[j][k]>=a))) {
siji(h,i+1,op) scanf("%d%d%s%d",&x,&y,s,&v);
puts("IMPOSSIBLE");
return;
}
if(s[0]=='=') {upp[j][k]=low[j][k]=v;disable[j][k]=1;}
else if(s[0]=='>') {low[j][k]=max(low[j][k],v);}
else {upp[j][k]=min(upp[j][k],v);}
}
}
}
else if(x==0) {
siji(j,1,r) {
if(disable[j][y] && (!(low[j][y]<=b && low[j][y]>=a))) {
siji(h,i+1,op) scanf("%d%d%s%d",&x,&y,s,&v);
puts("IMPOSSIBLE");
return;
}
if(s[0]=='=') {upp[j][y]=low[j][y]=v;disable[j][y]=1;}
else if(s[0]=='>') {low[j][y]=max(low[j][y],v);}
else {upp[j][y]=min(upp[j][y],v);}
}
}
else if(y==0) {
siji(k,1,c) {
if(disable[x][k] && (!(low[x][k]<=b && low[x][k]>=a))) {
siji(h,i+1,op) scanf("%d%d%s%d",&x,&y,s,&v);
puts("IMPOSSIBLE");
return;
}
if(s[0]=='=') {upp[x][k]=low[x][k]=v;disable[x][k]=1;}
else if(s[0]=='>') {low[x][k]=max(low[x][k],v);}
else {upp[x][k]=min(upp[x][k],v);}
}
}
else {
if(disable[x][y] && (!(low[x][y]<=b && low[x][y]>=a))) {
siji(h,i+1,op) scanf("%d%d%s%d",&x,&y,s,&v);
puts("IMPOSSIBLE");
return;
}
if(s[0]=='=') {upp[x][y]=low[x][y]=v;disable[x][y]=1;}
else if(s[0]=='>') {low[x][y]=max(low[x][y],v);}
else {upp[x][y]=min(upp[x][y],v);}
}
}
if(tot!=0) {puts("IMPOSSIBLE");return;}
siji(i,1,r) {
siji(j,1,c) {
d[i]-=low[i][j];
d[j+r]+=low[i][j];
if(low[i][j]>upp[i][j]) {puts("IMPOSSIBLE");return;}
addtwo(i,j+r,upp[i][j]-low[i][j]);
}
}
source=r+c+1,sink=r+c+2;
tot=0;
siji(i,1,r+c) {
if(d[i]>0) addtwo(source,i,d[i]),tot+=d[i];
else if(d[i]<0) addtwo(i,sink,-d[i]);
}
while(dis[source]<sink) tot-=sap(source,tot);
if(tot) {puts("IMPOSSIBLE");return;}
siji(i,1,r) {
siji(j,1,c) {
int id=((i-1)*c+j)*2+1;
printf("%d%c",low[i][j]+edge[id].val," \n"[j==c]);
}
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
int T,cnt=0;
scanf("%d",&T);
while(T--) {
++cnt;
if(cnt!=1) puts("");
solve();
}
return 0;
}
这道题需要先从终点到起点连一条容量下界为0上界是inf的边,然后做一遍有无源汇的可行流
然后从s到t在残余网络做一遍最大流,开始时如果终点到起点有流的话,这条流还会被退回去
SPJ挂了,垃圾题,可我代码都写完了
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define MAXN 40005
//#define ivorysi
using namespace std;
typedef long long ll;
struct node {
int to,next,val;
}edge[400005];
int head[MAXN],sumedge,n,m,source,sink,S,T,maxnum;
int dis[MAXN],gap[MAXN],d[MAXN],pos[MAXN],ans[MAXN],cnt;
void add(int u,int v,int c) {
edge[++sumedge].to=v;
edge[sumedge].next=head[u];
edge[sumedge].val=c;
head[u]=sumedge;
}
void addtwo(int u,int v,int c) {
add(u,v,c);add(v,u,0);
}
int sap(int u,int aug,int &Si,int &Ti) {
if(u==Ti) return aug;
int dmin=maxnum-1,flow=0;
for(int i=head[u];i;i=edge[i].next) {
if(edge[i].val>0) {
int v=edge[i].to;
if(dis[v]+1==dis[u]) {
int t=sap(v,min(aug-flow,edge[i].val),Si,Ti);
flow+=t;
edge[i].val-=t;
edge[i^1].val+=t;
if(flow==aug) return flow;
if(dis[Si]>=maxnum) return flow;
}
dmin=min(dmin,dis[v]);
}
}
if(!flow) {
gap[dis[u]]--;
if(gap[dis[u]]==0) dis[Si]=maxnum;
dis[u]=dmin+1;
gap[dis[u]]++;
}
return flow;
}
void solve() {
memset(head,0,sizeof(head));sumedge=1;
memset(d,0,sizeof(d));
memset(ans,0,sizeof(ans));
memset(pos,0,sizeof(pos));
cnt=0;
source=1,sink=n+m+2;
int x;
siji(i,1,m) {
scanf("%d",&x);
addtwo(n+1+i,sink,0x7fffffff);
d[sink]+=x;
d[n+1+i]-=x;
}
int C,D,t,l,r;
siji(i,1,n) {
scanf("%d%d",&C,&D);
addtwo(source,i+1,D);
siji(j,1,C) {
scanf("%d%d%d",&t,&l,&r);++t;
++cnt;
addtwo(i+1,t+n+1,r-l);
pos[cnt]=sumedge;
ans[cnt]=l;
d[i+1]-=l;
d[t+n+1]+=l;
}
}
addtwo(sink,source,0x7fffffff);
S=sink+1,T=sink+2;
int tot=0;
siji(i,1,n+m+2) {
if(d[i]>0) {addtwo(S,i,d[i]);tot+=d[i];}
else if(d[i]<0) addtwo(i,T,-d[i]);
}
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
maxnum=n+m+4;
while(dis[S]<maxnum) tot-=sap(S,tot,S,T);
if(tot) {puts("-1");return;}
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
while(dis[source]<maxnum) tot+=sap(source,0x7fffffff,source,sink);
printf("%d\n",tot);
siji(i,1,cnt) {
ans[i]+=edge[pos[i]].val;
printf("%d\n",ans[i]);
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
while(scanf("%d",&n)!=EOF) {
scanf("%d",&m);
solve();
puts("");
}
return 0;
}
Time Limit: 2 Seconds Memory Limit: 65536 KB
Company A wants to transport as many goods as possible from city S to city T. So they ask company B to do the transportation. There are n cities here in the problem and there are directed roads from cities i to city j with capacity cij.
After a long negotiation, A and B reach a consensus that A first decide how to transport the goods (Of course under the condition that most goods are transported and that the quantity transported in each road cannot exceed the capacity) and then B can assign non-negative integer unit transportation costs to each road such that the total unit transportation costs in all roads sum to P. So the money A has to pay is the sum of costs of all roads while the cost of a certain road is the quantity transported (assigned by A) multiplied by the unit transportation cost (assigned by B). Notice that since the goods are not divisible, the quantity transported for each road should be a non-negative integer.
Of course A wants to minimize the cost and B want to maximize the cost. So you are to work out what the total cost will be?
To make the problem more fun, you should also work out the total cost that A wants to maximize the cost while B wants to minimize it and other conditions keep the same.
There are multiple test cases. The first line of the input is an integer T ≈ 100 indicating the number of test cases.
For each test case, the first line contains 5 integers n, m, S, T, P (2 ≤ n ≤ 500, 0 ≤ m ≤ 10000, 0 ≤ S, T < n, 0 ≤ P ≤ 100000). The next m lines describe the roads between cities. In each of the m lines, 3 integers u, v, c (0 ≤ u, v, 1 ≤ c ≤ 100000) are given indicating a road from u to v with capacity c.
For each test case, output one line with two integers. The first is the total cost that A wants to minimize and B wants to maximize, the second is the total cost that A wants to maximize and B wants to minimize.
1
5 5 0 4 1
0 3 1
0 2 1
3 1 1
2 1 1
1 4 1
1 0
A can assign the transported quantity in roads to (1, 0, 1, 0, 1) or (0, 1, 0, 1, 1) in the order as the input. Both of the assignment can transport 1 unit of goods.
So in the first situation, B can assign 1 unit cost to a road that transport 1 unit of goods and 0 to other roads. The total cost is 1. In the second situation, B can assign 1 unit cost to a road that transport 0 units of goods and 0 to other roads. The total cost is 0.
这道题一看就是二分……然而题面有点绕,导致我没有仔细读题
"Of course under the condition that most goods are transported and that the quantity transported in each road cannot exceed the capacity"告诉我们要求货物的运输量不管怎么样都要最大
“then B can assign non-negative integer unit transportation costs to each road such that the total unit transportation costs in all roads sum to P”
A公司设定运输计划
B公司会在一些道路上增加单位花费,共计加上P
然后A公司去运输,交给B公司钱
求两个东西,一个是A公司希望花费最小B公司希望花费最大
一个是B公司希望花费最小A公司希望花费最大
实际上B公司只需要把A公司流量最大的那条边设成P就好,这样A公司花费最大,A公司需要让最大值最小
第二个B公司把A公司流量最小的那条边设成P,A公司花费最小,A公司需要让最小值最大
先求出最大流
二分答案
然后对于一个问题二分上界,直接做网络流
对第二个问题二分下界,做有上下界的网络流,求最大流,和一开始求出的最大流比较是否相等
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
//#define ivorysi
using namespace std;
typedef long long ll;
struct node {
int to,next,val;
}edge[400005];
int head[505],sumedge,d[505],dis[505],gap[505],maxnum;
struct data {
int u,v,c;
}Eg[100005];
int n,m,S,T,P,source,sink,Maxflow;
void add(int u,int v,int c) {
edge[++sumedge].to=v;
edge[sumedge].next=head[u];
edge[sumedge].val=c;
head[u]=sumedge;
}
void addtwo(int u,int v,int c) {
add(u,v,c);add(v,u,0);
}
int sap(int u,int aug,int &Si,int &Ti) {
if(u==Ti) return aug;
int dmin=maxnum-1,flow=0;
for(int i=head[u];i;i=edge[i].next) {
if(edge[i].val>0) {
int v=edge[i].to;
if(dis[v]+1==dis[u]) {
int t=sap(v,min(aug-flow,edge[i].val),Si,Ti);
flow+=t;
edge[i].val-=t;
edge[i^1].val+=t;
if(flow==aug) return flow;
if(dis[Si]>=maxnum) return flow;
}
dmin=min(dmin,dis[v]);
}
}
if(!flow) {
--gap[dis[u]];
if(gap[dis[u]]==0) dis[Si]=maxnum;
dis[u]=dmin+1;
++gap[dis[u]];
}
return flow;
}
void getmaxflow() {
memset(head,0,sizeof(head));sumedge=1;
memset(gap,0,sizeof(gap));
memset(dis,0,sizeof(dis));
siji(i,1,m) {
addtwo(Eg[i].u,Eg[i].v,Eg[i].c);
}
Maxflow=0;
while(dis[S]<maxnum) Maxflow+=sap(S,0x7fffffff,S,T);
}
bool check1(int up) {
memset(head,0,sizeof(head));sumedge=1;
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
siji(i,1,m) {
addtwo(Eg[i].u,Eg[i].v,min(up,Eg[i].c));
}
int tot=0;
while(dis[S]<maxnum) tot+=sap(S,0x7fffffff,S,T);
return tot==Maxflow;
}
bool check2(int low) {
memset(head,0,sizeof(head));sumedge=1;
memset(d,0,sizeof(d));
siji(i,1,m) {
if(Eg[i].c<low) return false;
d[Eg[i].u]-=low;
d[Eg[i].v]+=low;
addtwo(Eg[i].u,Eg[i].v,Eg[i].c-low);
}
addtwo(T,S,0x7fffffff);
int tot=0;
siji(i,1,n) {
if(d[i]>0) addtwo(source,i,d[i]),tot+=d[i];
else if(d[i]<0) addtwo(i,sink,-d[i]);
}
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
while(dis[source]<maxnum) tot-=sap(source,tot,source,sink);
if(tot) return false;
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
while(dis[S]<maxnum) tot+=sap(S,0x7fffffff,S,T);
return tot==Maxflow;
}
void solve() {
scanf("%d%d%d%d%d",&n,&m,&S,&T,&P);
source=n+1,sink=n+2;
maxnum=n+2;
++S;++T;
int rmax=0;
siji(i,1,m) {
scanf("%d%d%d",&Eg[i].u,&Eg[i].v,&Eg[i].c);
++Eg[i].u;++Eg[i].v;
rmax=max(rmax,Eg[i].c);
}
if(m==0) {
puts("0 0");return;
}
getmaxflow();
if(Maxflow == 0) {
puts("0 0");return;
}
int l=0,r=rmax;
while(l<r) {
int mid=(l+r)>>1;
if(check1(mid)) r=mid;
else l=mid+1;
}
printf("%lld ",1LL*r*P);
l=0,r=rmax;
while(l<r) {
int mid=(l+r+1)>>1;
if(check2(mid)) l=mid;
else r=mid-1;
}
printf("%lld\n",1LL*l*P);
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
int T,cnt=0;
scanf("%d",&T);
while(T--) {
solve();
}
return 0;
}
这道题还可以看成无源汇的可行流来做,从汇点到源点流一条下界为最大流流量的边,然后判断是否合法
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
//#define ivorysi
using namespace std;
typedef long long ll;
struct node {
int to,next,val;
}edge[400005];
int head[505],sumedge,d[505],dis[505],gap[505],maxnum;
struct data {
int u,v,c;
}Eg[100005];
int n,m,S,T,P,source,sink,Maxflow;
void add(int u,int v,int c) {
edge[++sumedge].to=v;
edge[sumedge].next=head[u];
edge[sumedge].val=c;
head[u]=sumedge;
}
void addtwo(int u,int v,int c) {
add(u,v,c);add(v,u,0);
}
int sap(int u,int aug,int &Si,int &Ti) {
if(u==Ti) return aug;
int dmin=maxnum-1,flow=0;
for(int i=head[u];i;i=edge[i].next) {
if(edge[i].val>0) {
int v=edge[i].to;
if(dis[v]+1==dis[u]) {
int t=sap(v,min(aug-flow,edge[i].val),Si,Ti);
flow+=t;
edge[i].val-=t;
edge[i^1].val+=t;
if(flow==aug) return flow;
if(dis[Si]>=maxnum) return flow;
}
dmin=min(dmin,dis[v]);
}
}
if(!flow) {
--gap[dis[u]];
if(gap[dis[u]]==0) dis[Si]=maxnum;
dis[u]=dmin+1;
++gap[dis[u]];
}
return flow;
}
void getmaxflow() {
memset(head,0,sizeof(head));sumedge=1;
memset(gap,0,sizeof(gap));
memset(dis,0,sizeof(dis));
siji(i,1,m) {
addtwo(Eg[i].u,Eg[i].v,Eg[i].c);
}
Maxflow=0;
while(dis[S]<maxnum) Maxflow+=sap(S,0x7fffffff,S,T);
}
bool check1(int up) {
memset(head,0,sizeof(head));sumedge=1;
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
siji(i,1,m) {
addtwo(Eg[i].u,Eg[i].v,min(up,Eg[i].c));
}
addtwo(source,S,Maxflow);
addtwo(T,sink,Maxflow);
int tot=Maxflow;
while(dis[source]<maxnum) tot-=sap(source,tot,source,sink);
return !tot;
}
bool check2(int low) {
memset(head,0,sizeof(head));sumedge=1;
memset(d,0,sizeof(d));
siji(i,1,m) {
if(Eg[i].c<low) return false;
d[Eg[i].u]-=low;
d[Eg[i].v]+=low;
addtwo(Eg[i].u,Eg[i].v,Eg[i].c-low);
}
d[S]+=Maxflow;
d[T]-=Maxflow;
int tot=0;
siji(i,1,n) {
if(d[i]>0) addtwo(source,i,d[i]),tot+=d[i];
else if(d[i]<0) addtwo(i,sink,-d[i]);
}
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
while(dis[source]<maxnum) tot-=sap(source,tot,source,sink);
return !tot;
}
void solve() {
scanf("%d%d%d%d%d",&n,&m,&S,&T,&P);
source=n+1,sink=n+2;
maxnum=n+2;
++S;++T;
int rmax=0;
siji(i,1,m) {
scanf("%d%d%d",&Eg[i].u,&Eg[i].v,&Eg[i].c);
++Eg[i].u;++Eg[i].v;
rmax=max(rmax,Eg[i].c);
}
if(m==0) {
puts("0 0");return;
}
getmaxflow();
if(Maxflow == 0) {
puts("0 0");return;
}
int l=0,r=rmax;
while(l<r) {
int mid=(l+r)>>1;
if(check1(mid)) r=mid;
else l=mid+1;
}
printf("%lld ",1LL*r*P);
l=0,r=rmax;
while(l<r) {
int mid=(l+r+1)>>1;
if(check2(mid)) l=mid;
else r=mid-1;
}
printf("%lld\n",1LL*l*P);
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
int T,cnt=0;
scanf("%d",&T);
while(T--) {
solve();
}
return 0;
}
You’ve just built a circuit board for your new robot, and now you need to power it. Your robot circuit consists of a number of electrical components that each require a certain amount of current to operate. Every component has a + and a - lead, which are connected on the circuit board at junctions. Current flows through the component from + to - (but note that a component does not "use up" the current: everything that comes in through the + end goes out the - end).
The junctions on the board are labeled 1, ..., N, except for two special junctions labeled + and - where the power supply terminals are connected. The + terminal only connects + leads, and the - terminal only connects - leads. All current that enters a junction from the - leads of connected components exits through connected + leads, but you are able to control how much current flows to each connected + lead at every junction (though methods for doing so are beyond the scope of this problem1). Moreover, you know you have assembled the circuit in such a way that there are no feedback loops (components chained in a manner that allows current to flow in a loop).
Figure 1: Examples of two valid circuit diagrams.
In (a), all components can be powered along directed paths from the positive terminal to the negative terminal.
In (b), components 4 and 6 cannot be powered, since there is no directed path from junction 4 to the negative terminal.
In the interest of saving power, and also to ensure that your circuit does not overheat, you would like to use as little current as possible to get your robot to work. What is the smallest amount of current that you need to put through the + terminal (which you can imagine all necessarily leaving through the - terminal) so that every component on your robot receives its required supply of current to function?
1 For those who are electronics-inclined, imagine that you have the ability to adjust the potential on any componentwithout altering its current requirement, or equivalently that there is an accurate variable potentiometer connected in series with each component that you can adjust. Your power supply will have ample potential for the circuit.
The input file will contain multiple test cases. Each test case begins with a single line containing two integers: N (0 <= N <= 50), the number of junctions not including the positive and negative terminals, and M (1 <= M <= 200), the number of components in the circuit diagram. The next M lines each contain a description of some component in the diagram. The ith component description contains three fields: pi, the positive junction to which the component is connected, ni, the negative junction to which the component is connected, and an integer Ii (1 <= Ii <= 100), the minimum amount of current required for component i to function. The junctions pi and ni are specified as either the character '+' indicating the positive terminal, the character '-' indicating the negative terminal, or an integer (between 1 and N) indicating one of the numbered junctions. No two components have the same positive junction and the same negative junction. The end-of-file is denoted by an invalid test case with N = M = 0 and should not be processed.
For each input test case, your program should print out either a single integer indicating the minimum amount of current that must be supplied at the positive terminal in order to ensure that every component is powered, or the message "impossible" if there is no way to direct a sufficient amount of current to each component simultaneously.
6 10
+ 1 1
1 2 1
1 3 2
2 4 5
+ - 1
4 3 2
3 5 5
4 6 2
5 - 1
6 5 3
4 6
+ 1 8
1 2 4
1 3 5
2 4 6
3 - 1
3 4 3
0 0
9
impossible
这是一道有上下界的网络流有源汇求最小流
我们按照无源汇的可行流来做,只是一开始不加上汇点到源点的那条边
然后在加上源点到汇点那条下界为0上界为正无穷的边,再跑一次最大流,新加入的边的反边里的流量就是最小流
为什么呢,因为一开始做可行流的时候最大限度的计算了可以互相补偿下界使得流量平衡的流,然后再加上那条边使得从源点到汇点流过的流量尽可能小
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
//#define ivorysi
using namespace std;
typedef long long ll;
struct node {
int to,next,val;
}edge[10005];
int sumedge,head[55];
void add(int u,int v,int c) {
edge[++sumedge].to=v;
edge[sumedge].next=head[u];
edge[sumedge].val=c;
head[u]=sumedge;
}
void addtwo(int u,int v,int c) {
add(u,v,c);add(v,u,0);
}
int source,sink,n,m,dis[55],gap[55],d[55];
char s1[10],s2[10];
int sap(int u,int aug) {
if(u==sink) return aug;
int dmin=sink-1,flow=0;
for(int i=head[u];i;i=edge[i].next) {
if(edge[i].val>0) {
int v=edge[i].to;
if(dis[v]+1==dis[u]) {
int t=sap(v,min(edge[i].val,aug-flow));
flow+=t;
edge[i].val-=t;
edge[i^1].val+=t;
if(flow==aug) return flow;
if(dis[source]>=sink) return flow;
}
dmin=min(dmin,dis[v]);
}
}
if(!flow) {
--gap[dis[u]];
if(gap[dis[u]]==0) dis[source]=sink;
dis[u]=dmin+1;
++gap[dis[u]];
}
return flow;
}
void solve() {
memset(head,0,sizeof(head));sumedge=1;
memset(d,0,sizeof(d));
source=n+3;sink=n+4;
int u,v,c;
siji(i,1,m) {
scanf("%s%s%d",s1+1,s2+1,&c);
if(s1[1]=='+') u=n+1;
else sscanf(s1+1,"%d",&u);
if(s2[1]=='-') v=n+2;
else sscanf(s2+1,"%d",&v);
d[u]-=c;
d[v]+=c;
addtwo(u,v,0x7fffffff);
}
int tot=0;
siji(i,1,n+2) {
if(d[i]>0) addtwo(source,i,d[i]),tot+=d[i];
else if(d[i]<0) addtwo(i,sink,-d[i]);
}
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
while(dis[source]<sink) tot-=sap(source,tot);
addtwo(n+2,n+1,0x7fffffff);
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
while(dis[source]<sink) tot-=sap(source,tot);
if(tot) puts("impossible");
else {
printf("%d\n",edge[sumedge].val);
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
while(scanf("%d%d",&n,&m)!=EOF) {
if(n+m==0) break;
solve();
}
return 0;
}