网络流24题

挑战中

 

问题编号

问题名称

问题模型

转化模型

1

飞行员配对方案问题

二分图最大匹配

网络最大流 

2

太空飞行计划问题

最大权闭合图

网络最小割 

3

最小路径覆盖问题

有向无环图最小路径覆盖

网络最大流     

4

魔术球问题

有向无环图最小路径覆盖

网络最大流 

5

圆桌问题

二分图多重匹配

网络最大流 

6

最长递增子序列问题

最多不相交路径

网络最大流

7

试题库问题

二分图多重匹配

网络最大流      

8

机器人路径规划问题

(未解决)

最小费用最大流

9

方格取数问题

二分图点权最大独立集

网络最小割

10

餐巾计划问题

线性规划网络优化

最小费用最大流

11

航空路线问题

最长不相交路径

最小费用最大流

12

软件补丁问题

最小转移代价

最短路径

13

星际转移问题

网络判定

网络最大流

14

孤岛营救问题

分层图最短路径

最短路径

15

汽车加油行驶问题

分层图最短路径

最短路径

16

数字梯形问题

最大权不相交路径

最小费用最大流

17

运输问题

网络费用流量

最小费用最大流

18

分配问题

二分图最佳匹配

最小费用最大流

19

负载平衡问题

最小代价供求

最小费用最大流

20

深海机器人问题

线性规划网络优化

最小费用最大流

21

最长k可重区间集问题

最大权不相交路径

最小费用最大流

22

最长k可重线段集问题

最大权不相交路径

最小费用最大流

23

火星探险问题

线性规划网络优化

最小费用最大流

24

骑士共存问题

二分图最大独立集

网络最小割

1. 飞行员配对方案问题

https://www.oj.swust.edu.cn/problem/show/1736

二分图最大匹配。超级源点连外籍飞行员,容量为1。匹配的外籍和英国飞行员间连一条边,容量为1。英国飞行员与超级汇点连一条边,容量为1。跑最大流,输出匹配的对。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define IOS ios::sync_with_stdio(0);cin.tie(0);
#define random(a, b) rand()*rand()%(b-a+1)+a
#define pi acos(-1)
const ll INF = 0x3f3f3f3f3f3f3f3fll;
const int inf = 0x3f3f3f3f;
const int maxn = 1000 + 10;
const int maxm = 3000000 +10;
const int mod = 1000000000;

int maze[maxn][maxn];
int gap[maxn],dis[maxn],pre[maxn],cur[maxn];
int sap(int start,int ed,int nodenum){
    memset(cur,0,sizeof(cur));
    memset(dis,0,sizeof(dis));
    memset(gap,0,sizeof(gap));
    int u = pre[start]=start,maxflow=0,aug=-1;
    gap[0]=nodenum;
    while(dis[start]<nodenum){
        loop:
            for(int v =cur[u];v<nodenum;v++){
                if(maze[u][v]&&dis[u]==dis[v]+1){
                    if(aug==-1||aug>maze[u][v]) aug = maze[u][v];
                    pre[v]=u;
                    u=cur[u]=v;
                    if(v==ed){
                        maxflow+=aug;
                        for(u=pre[u];v!=start;v=u,u=pre[u]){
                            maze[u][v]-=aug;
                            maze[v][u]+=aug;
                        }
                        aug=-1;
                    }
                    goto loop;
                }
            }
            int mindis = nodenum-1;
            for(int v=0;v<nodenum;v++){
                if(maze[u][v]&&mindis>dis[v]){
                    cur[u]=v;
                    mindis=dis[v];
                }
            }
            if((--gap[dis[u]])==0) break;
            gap[dis[u]=mindis+1]++;
            u=pre[u];
    }
    return maxflow;
}

int main(){
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif // LOCAL
    int n,m;
    while(~scanf("%d%d",&m,&n)){
        memset(maze,0,sizeof(maze));
        for(int i=1;i<=m;i++) maze[0][i]=1;
        for(int i=m+1;i<=n;i++) maze[i][n+1]=1;
        int x,y;
        while(true){
            scanf("%d%d",&x,&y);
            if(x==-1&&y==-1) break;
            maze[x][y]=1;
        }
        int ans=sap(0,n+1,n+2);
        cout<<ans<<endl;

        for(int i=1;i<=m;i++){
            for(int j=m+1;j<=n;j++){
                if(maze[i][j]==0&&maze[j][i]==1){
                    printf("%d %d
",i,j);
                    break;
                }
            }
        }
    }
    return 0;
}

 2.太空飞行计划问题

https://www.oj.swust.edu.cn/problem/show/1737

有一个有向图,每一个点都有一个权值(可以为正或负或0),选择一个权值和最大的子图,使得每个点的后继都在子图里面,这个子图就叫最大权闭合子图

这题就是求最大权闭合子图,转化为最小割来解决。把S向正费用点连边,T向负费用点连边,原图的边间连+oo

然后做最小割=min(未选收益+选花费)

答案=选收益-选花费=全选收益-(未选收益+选花费)

最大权闭合图的点就是从起点开始广搜,权值为0的点不走,能走到的点就是被选中的点。

dinic最后一次bfs的dep数组正好可以用来判断这个条件。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define IOS ios::sync_with_stdio(0);cin.tie(0);
#define random(a, b) rand()*rand()%(b-a+1)+a
#define pi acos(-1)
const ll INF = 0x3f3f3f3f3f3f3f3fll;
const int inf = 0x3f3f3f3f;
const int maxn = 2000 + 10;
const int maxm = 1000000 +10;
const int mod = 1000000000;

struct Edge{
    int to,nxt,cap,flow;
}edge[maxm];
int tol;
int head[maxn];
void init(){
    tol = 2;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw=0){
    edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=0;
    edge[tol].nxt=head[u];head[u]=tol++;
    edge[tol].to=u;edge[tol].cap=rw;edge[tol].flow=0;
    edge[tol].nxt=head[v];head[v]=tol++;
}
int Q[maxn];
int dep[maxn],cur[maxn],sta[maxn];
bool bfs(int s,int t,int n){
    int fron=0,tail=0;
    memset(dep,-1,sizeof(dep[0])*(n+1));
    dep[s]=0;
    Q[tail++]=s;
    while(fron<tail){
        int u =Q[fron++];
        for(int i=head[u];~i;i=edge[i].nxt){
            int v =edge[i].to;
            if(edge[i].cap>edge[i].flow&&dep[v]==-1){
                dep[v]=dep[u]+1;
                if(v==t) return true;
                Q[tail++]=v;
            }
        }
    }
    return false;
}
int dinic(int s,int t,int n){
    int maxflow=0;
    while(bfs(s,t,n)){
        for(int i=0;i<n;i++) cur[i]=head[i];
        int u=s,tail=0;
        while(cur[s]!=-1){
            if(u==t){
                int tp=inf;
                for(int i=tail-1;i>=0;i--){
                    tp=min(tp,edge[sta[i]].cap-edge[sta[i]].flow);
                }
                maxflow+=tp;
                for(int i=tail-1;i>=0;i--){
                    edge[sta[i]].flow+=tp;
                    edge[sta[i]^1].flow-=tp;
                    if(edge[sta[i]].cap-edge[sta[i]].flow==0) tail=i;
                }
                u=edge[sta[tail]^1].to;
            }else if(cur[u]!=-1&&edge[cur[u]].cap>edge[cur[u]].flow&&dep[u]+1==dep[edge[cur[u]].to]){
                sta[tail++]=cur[u];
                u=edge[cur[u]].to;
            }else{
                while(u!=s&&cur[u]==-1){
                    u=edge[sta[--tail]^1].to;
                }
                cur[u]=edge[cur[u]].nxt;
            }
        }
    }
    return maxflow;
}
int main(){
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif // LOCAL
    int n,m;
    init();
    scanf("%d%d",&m,&n);
    int sum=0;
    for(int i=1;i<=m;i++){
        int x;
        char c;
        scanf("%d",&x);
        sum+=x;
        addedge(0,i,x);
        while(true){
            scanf("%d%c",&x,&c);
            addedge(i,m+x,inf);
            if(c=='
'||c=='
') break;
        }
    }
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        addedge(i+m,n+m+1,x);
    }
    sum-=dinic(0,n+m+1,n+m+2);

    for(int i=1;i<=m;i++) if(dep[i]!=-1) printf("%d ",i);
    puts("");
    for(int i=1;i<=n;i++) if(dep[i+m]!=-1) printf("%d ",i);
    puts("");
    printf("%d
",sum);
    return 0;
}
原文地址:https://www.cnblogs.com/fht-litost/p/9709376.html