網絡流24題

挑戰中node

 

問題編號ios

問題名稱數組

問題模型網絡

轉化模型dom

1oop

飛行員配對方案問題優化

二分圖最大匹配spa

網絡最大流 code

2blog

太空飛行計劃問題

最大權閉合圖

網絡最小割 

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\n",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=='\n'||c=='\r') 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\n",sum);
    return 0;
}
相關文章
相關標籤/搜索