# 网络流入门之简单建模（2）

### 1）最大流模板题（loj#101）：

7 14 1 7
1 2 5
1 3 6
1 4 5
2 3 2
2 5 3
3 2 2
3 4 3
3 5 3
3 6 7
4 6 5
5 6 1
6 5 1
5 7 8
6 7 7

14

1⩽n⩽100,1⩽m⩽5000,0⩽c⩽2^31-1

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int get(){register int re=0,f=1;register char c;while(c=getchar(),(c>='0'&&c<='9')^1)f=c^'-';while(re=(re<<1)+(re<<3)+(c^48),c=getchar(),(c>='0'&&c<='9'));return f?re:-re;}
const int N = 1e6+10;
struct edge{
int to,cap;
};
struct Dninc{
int n,m,s,t;
int d[N],cur[N];
vector<int>G[N];
vector<edge>edges;
inline void add(int u,int v,int cap){
edges.push_back((edge){v,cap});
edges.push_back((edge){u,0});
int sz=edges.size();
G[u].push_back(sz-2);
G[v].push_back(sz-1);
}
inline void init(){
n=get(),m=get(),s=get(),t=get();
while(m--){
int u=get(),v=get(),cap=get();
}
}
inline bool bfs(){
memset(d,-1,sizeof(d));
queue<int>Q;
Q.push(s);
d[s]=0;
while(!Q.empty()){
int x=Q.front();Q.pop();
int sz=G[x].size();
for(int i=0;i<sz;i++){
edge e=edges[G[x][i]];
if(d[e.to]==-1&&e.cap>0){
d[e.to]=d[x]+1;
Q.push(e.to);
}
}
}return d[t]!=-1;
}
inline int dfs(int x,int Maxf){
if(x==t||Maxf==0)return Maxf;
int f,ret=0,sz=G[x].size();
for(int& i=cur[x];i<sz;i++){
edge &e=edges[G[x][i]];
if(d[e.to]==d[x]+1&&(f=dfs(e.to,min(Maxf,e.cap)))>0){
edges[G[x][i]^1].cap+=f;
e.cap-=f;
Maxf-=f;
ret+=f;
if(Maxf==0)break;
}
}return ret;
}
inline void solv(){
int flow=0;
while(bfs()){
memset(cur,0,sizeof(cur));
flow+=dfs(s,1<<30);
}cout<<flow<<"\n";
}
}z;
main(){
z.init();
z.solv();
return 0;
}

2）网络流24题之飞行员搭配（loj#6000）：

10 5
1 7
2 6
2 10
3 7
4 8
5 9

4

2≤n≤10.

#include<bits/stdc++.h>
using namespace std;
inline int get(){register int re=0,f=1;register char c;while(c=getchar(),(c>='0'&&c<='9')^1)f=c^'-';while(re=(re<<1)+(re<<3)+(c^48),c=getchar(),(c>='0'&&c<='9'));return f?re:-re;}
const int N = 1010;
struct edge{
int to,cap;
};
struct Dinic{
int n,m,s,t;
int d[N],cur[N];
vector<int>G[N];
vector<edge>edges;
inline void add(int u,int v,int cap){
edges.push_back((edge){v,cap});
edges.push_back((edge){u,0});
int sz=edges.size();
G[u].push_back(sz-2);
G[v].push_back(sz-1);
}
inline void init(){
n=get(),m=n-get(),n-=m,s=0,t=n+m+1;
int u,v;
}
inline bool bfs(){
memset(d,-1,sizeof(d));
queue<int>Q;
Q.push(s);
d[s]=0;
while(!Q.empty()){
int x=Q.front();Q.pop();
int sz=G[x].size();
for(int i=0;i<sz;i++){
edge e=edges[G[x][i]];
if(d[e.to]==-1&&e.cap>0){
d[e.to]=d[x]+1;
Q.push(e.to);
}
}
}return d[t]!=-1;
}
inline int dfs(int x,int Maxf){
if(x==t||Maxf==0)return Maxf;
int f,ret=0,sz=G[x].size();
for(int& i=cur[x];i<sz;i++){
edge &e=edges[G[x][i]];
if(d[e.to]==d[x]+1&&(f=dfs(e.to,min(Maxf,e.cap)))>0){
edges[G[x][i]^1].cap+=f;
e.cap-=f;
Maxf-=f;
ret+=f;
if(Maxf==0)break;
}
}return ret;
}
inline void solv(){
int flow=0;
while(bfs()){
memset(cur,0,sizeof(cur));
flow+=dfs(s,1<<30);
}cout<<flow<<"\n";
}
}z;
int main(){
z.init();
z.solv();
return 0;
}

3）pigs（poj#1149/bsoj#2536）：

Description

尼克在一家养猪场工作，这家养猪场共有M间锁起来的猪舍，由于猪舍的钥匙都给了客户，所以尼克没有办法打开这些猪舍，客户们从早上开始一个接一个来购买生猪，他们到达后首先用手中的钥匙打开他所能打开的全部猪舍，然后从中选取他要买的生猪，尼克可以在此期间将打开的猪舍中的猪调整到其它开着的猪舍中，每个猪舍能存放的猪的数量是没有任何限制的。买完猪后客户会将他打开的猪舍关上。
好在尼克事先知道每位客户手中有哪些钥匙，要买多少猪，以及客户到来的先后次序。请你写一个程序，帮助尼克求出最多能卖出多少头生猪。

Input

输入文件的第一行包含两个整数M和N，1≤M≤1000，1≤N≤100，M为猪舍的数量，N为客户人数，猪舍的编号为1到M，客户的编号为1到N。
输入文件第二行包含M个空格隔开的整数，依次表示每个猪舍中的生猪数量，每个整数大于等于0，且小于等于1000。
接下来的N行每行表示一位客户的购买信息，第I个客户的购买信息位于第I+2行，其格式如下：
A K1 K2……KA B
它表示该客户共有A把钥匙，钥匙编号依次为K1，K2……KA，且K1 < K2 <……< KA，B为该客户要买的生猪的头数。

Output

输出文件仅有一行包含一个整数，表示尼克最多能卖出的生猪的头数。

Sample Input

3 3

3 1 10

2 1 2 2

2 1 3 3

1 2 6

Sample Output

7

• 三个顾客，就有三轮交易，每一轮分别都有 3 个猪圈和 1 个顾客的结点。

• 从源点到第一轮的各个猪圈各有一条边，容量就是各个猪圈里的猪的初始数量。

• 从各个顾客到汇点各有一条边，容量就是各个顾客能买的数量上限。

• 在某一轮中，从该顾客打开的所有猪圈都有一条边连向该顾客，容量都是∞。

• 最后一轮除外，从每一轮的 i 号猪圈都有一条边连向下一轮的 i 号猪圈，容量都是∞，表示这一轮剩下的猪可以留到下一轮。

• 最后一轮除外，从每一轮被打开的所有猪圈，到下一轮的同样这些猪圈，两两之间都要连一条边，表示它们之间可以任意流通。

//暴力
#include<bits/stdc++.h>
using namespace std;
inline int get(){register int re=0,f=1;register char c;while(c=getchar(),(c>='0'&&c<='9')^1)f=c^'-';while(re=(re<<1)+(re<<3)+(c^48),c=getchar(),(c>='0'&&c<='9'));return f?re:-re;}
const int N = 1e6+10,inf = 0x3f3f3f3f;
struct edge{
int to,cap;
};
struct Dninc{
int n,m,s,t;
bool vis[1010];
int d[N],cur[N];
vector<int>G[N];
vector<edge>edges;
inline void add(int u,int v,int cap){
edges.push_back((edge){v,cap});
edges.push_back((edge){u,0});
int sz=edges.size();
G[u].push_back(sz-2);
G[v].push_back(sz-1);
}
inline void init(){
m=get(),n=get();
s=0;t=n*m+n+1;
for(int i=1;i<=n;i++){
int num=get();
memset(vis,0,sizeof(vis));
vector<int>id;
id.clear();
for(int j=0;j<num;j++){
id.push_back(get());
vis[id[j]]=1;
}
int sz=id.size();
if(i!=n){
for(int j=0;j<sz;j++)
for(int k=0;k<sz;k++){
}
}
}
}
inline bool bfs(){
memset(d,-1,sizeof(d));
queue<int>Q;
Q.push(s);
d[s]=0;
while(!Q.empty()){
int x=Q.front();Q.pop();
int sz=G[x].size();
for(int i=0;i<sz;i++){
edge e=edges[G[x][i]];
if(d[e.to]==-1&&e.cap>0){
d[e.to]=d[x]+1;
Q.push(e.to);
}
}
}return d[t]!=-1;
}
inline int dfs(int x,int Maxf){
if(x==t||Maxf==0)return Maxf;
int f,ret=0,sz=G[x].size();
for(int& i=cur[x];i<sz;i++){
edge &e=edges[G[x][i]];
if(d[e.to]==d[x]+1&&(f=dfs(e.to,min(Maxf,e.cap)))>0){
edges[G[x][i]^1].cap+=f;
e.cap-=f;
Maxf-=f;
ret+=f;
if(Maxf==0)break;
}
}return ret;
}
inline void solv(){
int flow=0;
while(bfs()){
memset(cur,0,sizeof(cur));
flow+=dfs(s,1<<30);
}cout<<flow<<"\n";
}
}z;
int main(){
z.init();
z.solv();
return 0;
}
/******************************/
//巧构
#include<bits/stdc++.h>
using namespace std;
inline int get(){register int re=0,f=1;register char c;while(c=getchar(),(c>='0'&&c<='9')^1)f=c^'-';while(re=(re<<1)+(re<<3)+(c^48),c=getchar(),(c>='0'&&c<='9'));return f?re:-re;}
const int N = 1010,inf = 0x3f3f3f3f;
struct edge{
int to,cap;
};
struct Dninc{
int n,m,s,t,pig[N],last[N];
int d[N],cur[N];
vector<int>G[N];
vector<edge>edges;
inline void add(int u,int v,int cap){
edges.push_back((edge){v,cap});
edges.push_back((edge){u,0});
int sz=edges.size();
G[u].push_back(sz-2);
G[v].push_back(sz-1);
}
inline void init(){
m=get(),n=get();
s=0,t=n+1;
for(int i=1;i<=m;i++)pig[i]=get();
for(int i=1;i<=n;i++){
int num=get();
for(int j=1;j<=num;j++){
int id=get();
}
}
inline bool bfs(){
memset(d,-1,sizeof(d));
queue<int>Q;
Q.push(s);
d[s]=0;
while(!Q.empty()){
int x=Q.front();Q.pop();
int sz=G[x].size();
for(int i=0;i<sz;i++){
edge e=edges[G[x][i]];
if(d[e.to]==-1&&e.cap>0){
d[e.to]=d[x]+1;
Q.push(e.to);
}
}
}return d[t]!=-1;
}
inline int dfs(int x,int Maxf){
if(x==t||Maxf==0)return Maxf;
int f,ret=0,sz=G[x].size();
for(int& i=cur[x];i<sz;i++){
edge &e=edges[G[x][i]];
if(d[e.to]==d[x]+1&&(f=dfs(e.to,min(Maxf,e.cap)))>0){
edges[G[x][i]^1].cap+=f;
e.cap-=f;
Maxf-=f;
ret+=f;
if(Maxf==0)break;
}
}return ret;
}
inline void solv(){
int flow=0;
while(bfs()){
memset(cur,0,sizeof(cur));
flow+=dfs(s,1<<30);
}cout<<flow<<"\n";
}
}z;
int main(){
z.init();
z.solv();
return 0;
}

4）k-联赛（bsoj#2313）：

Description

K-联赛职业足球俱乐部的球迷们都是有组织的训练有素的啦啦队员，就像红魔啦啦队一样(2002年韩日世界杯上韩国队的啦啦队)。这个赛季，经过很多场比赛以后，球迷们希望知道他们支持的球队是否还有机会赢得最后的联赛冠军。换句话说，球队是否可以通过某种特定的比赛结果最终取得最高的积分(获胜场次最多)。(允许出现多支队并列第一的情况。)
现在，给出每个队的胜负场数，wi和di，分别表示teami的胜场和负场(1≤i≤n)。还给出ai,j，表示teami和teamj之间还剩多少场比赛要进行(1≤i,j≤n)。这里，n表示参加联赛的队数，所有的队分别用1，2，…，n来编号。你的任务是找出所有还有可能获得冠军的球队。
所有队参加的比赛数是相同的，并且为了简化问题，你可以认为不存在平局(比赛结果只有胜或负两种)。

Input

第一行一个整数n(1≤n≤25)，表示联赛中的队数。
第二行2n个数，w1，d1，w2，d2，……，wn，dn，所有的数不超过100。
第三行n2个数，a1,1，a1,2，…，a1,n，a2,1，…，a2,2，a2,n，…，an,1，an,2，…，an,n，所有的数都不超过10。ai,j=aj,i，如果i=j，则ai,j=0。

Output

仅一行，输出所有可能获得冠军的球队，按其编号升序输出，中间用空格分隔。

Sample Input

3

2 0 1 1 0 2

0 2 2 2 0 2 2 2 0

Sample Output

1 2 3

Hint

【样例2】
kleague.in
3
4 0 2 2 0 4
0 1 1 1 0 1 1 1 0
kleague.out
1 2
【样例3】
kleague.in
4
0 3 3 1 1 3 3 0
0 0 0 2 0 0 1 0 0 1 0 0 2 0 0 0
kleague.out
2 4

s连比赛，容量为a[i][j]表示还有多少场比赛要打，比赛连接队伍容量为+oo表示该队可任得p点分数，队伍连t，容量为tot-w[i]，如果此时恰好满流，则说明比赛打完且各个队伍最终得分均没有超过tot，则第i支队就有可能是冠军，否则，必然不是冠军。

#include<bits/stdc++.h>
using namespace std;
inline int get(){register int re=0,f=1;register char c;while(c=getchar(),(c>='0'&&c<='9')^1)f=c^'-';while(re=(re<<1)+(re<<3)+(c^48),c=getchar(),(c>='0'&&c<='9'));return f?re:-re;}
const int N = 1010;
struct edge{
int to,cap;
};
struct Dinic{
int n,s,t,w[N],a[N][N];
int d[N],cur[N];
vector<int>G[N];
vector<edge>edges;
inline void add(int u,int v,int cap){
edges.push_back((edge){v,cap});
edges.push_back((edge){u,0});
int sz=edges.size();
G[u].push_back(sz-2);
G[v].push_back(sz-1);
}
inline void init(){
n=get(),s=0,t=n*n+n+1;
for(int i=1;i<=n;i++)w[i]=get(),get();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)a[i][j]=get();
}
inline bool bfs(){
memset(d,-1,sizeof(d));
queue<int>Q;
Q.push(s);
d[s]=0;
while(!Q.empty()){
int x=Q.front();Q.pop();
int sz=G[x].size();
for(int i=0;i<sz;i++){
edge e=edges[G[x][i]];
if(d[e.to]==-1&&e.cap>0)d[e.to]=d[x]+1,Q.push(e.to);
}
}return d[t]!=-1;
}
inline int dfs(int x,int Maxf){
if(x==t||Maxf==0)return Maxf;
int f,ret=0,sz=G[x].size();
for(int& i=cur[x];i<sz;i++){
edge& e=edges[G[x][i]];
if(d[e.to]==d[x]+1&&(f=dfs(e.to,min(e.cap,Maxf)))>0){
edges[G[x][i]^1].cap+=f;
e.cap-=f;
Maxf-=f;
ret+=f;
if(Maxf==0)break;
}
}return ret;
}
inline bool check(int idx){//枚举验证每一个答案
int tot=w[idx],full=0;
for(int i=1;i<=n;i++)tot+=a[idx][i];
for(int i=1;i<=n;i++)if(w[i]>tot)return 0;//特判可不写，但要考虑负权
edges.clear();
for(int i=0;i<=t;i++)G[i].clear();
for(int i=1;i<n;i++)if(i!=idx)
for(int j=i+1;j<=n;j++)if(j!=idx)
full+=a[i][j],
for(int i=1;i<=n;i++)if(i!=idx)
int flow=0;
while(bfs()){
memset(cur,0,sizeof(cur));
flow+=dfs(s,1<<30);
}return flow==full;
}
inline void solv(){
for(int i=1;i<=n;i++)
if(check(i))cout<<i<<" ";
}
}z;
int main(){
z.init();
z.solv();
return 0;
}

• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120