• 网络流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;
    }
  • 相关阅读:
    javascript 字符串与正则
    微信小程序 实现三级联动-省市区
    VUE图片懒加载-vue lazyload插件的简单使用
    移动端使用mint-ui loadmore实现下拉刷新上拉显示更多
    vue-cli创建的项目中引入第三方库报错 'caller', 'calle', and 'arguments' properties .....报错问题
    js判断两个数组是否相等
    234回文链表
    剑指 Offer 22. 链表中倒数第k个节点
    返回倒数第 k 个节点
    leetcode 179.最大数
  • 原文地址:https://www.cnblogs.com/fht-litost/p/9709376.html
Copyright © 2020-2023  润新知