SCUT - 48 - 飞行员的配对方案 - 费用流

https://scut.online/p/48

一道二分图匹配,跑费用流就可以过了(其实最大流都可以了)。

#include<bits/stdc++.h>
#define MAXN_ 5050
#define INF 0x3f3f3f3f
#define P pair<int,int>
using namespace std;
struct edge {
    int to,cap,cost,rev;
};
int n,m,flow,s,t,cap,res,cost,from,to,h[MAXN_];
std::vector<edge> G[MAXN_];
int dist[MAXN_],prevv[MAXN_],preve[MAXN_]; // 前驱节点和对应边
inline void add() {
    G[from].push_back((edge) {
        to,cap,cost,(int)G[to].size()
    });
    G[to].push_back((edge) {
        from,0,-cost,(int)G[from].size()-1
    });
} // 在vector 之中找到边的位置所在!
inline int read() {
    int x=0;
    char c=getchar();
    bool flag=0;
    while(c<'0'||c>'9') {
        if(c=='-')
            flag=1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
        x=(x<<3)+(x<<1)+c-'0';
        c=getchar();
    }
    return flag?-x:x;
}
inline void min_cost_flow(int s,int t,int f) {
    fill(h+1,h+1+n,0);
    while(f > 0) {
        priority_queue<P,vector<P>, greater<P> > D;
        memset(dist,INF,sizeof dist);
        dist[s] = 0;
        D.push(P(0,s));
        while(!D.empty()) {
            P now = D.top();
            D.pop();
            if(dist[now.second] < now.first)
                continue;
            int v = now.second;
            for(int i=0; i<(int)G[v].size(); ++i) {
                edge &e = G[v][i];
                if(e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) {
                    dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
                    prevv[e.to] = v;
                    preve[e.to] = i;
                    D.push(P(dist[e.to],e.to));
                }
            }
        }
        // 无法增广 , 就是找到了答案了!
        if(dist[t] == INF)
            break;
        for(int i=1; i<=n; ++i)
            h[i] += dist[i];
        int d = f;
        for(int v = t; v != s; v = prevv[v])
            d = min(d,G[prevv[v]][preve[v]].cap);
        f -= d;
        flow += d;
        res += d * h[t];
        for(int v=t; v!=s; v=prevv[v]) {
            edge &e = G[prevv[v]][preve[v]];
            e.cap -= d;
            G[v][e.rev].cap += d;
        }
    }
}
int main() {
    int n1,n;
    scanf("%d",&n1);
    scanf("%d",&n);



    //n = read();
    //m = read();
    //s = read();
    //t = read();
    s=0;
    t=n+1;
    while(1) {
        from = read();
        to = read();
        if(from==-1&&to==-1)
            break;
        //cap = read();
        //cost = read();
        cap=1;
        cost=1;
        add();
    }

    for(int i=1;i<=n1;i++){
        from=s;
        to=i;
        cap=1;
        cost=1;
        add();
    }

    for(int i=n1+1;i<=n;i++){
        from=i;
        to=t;
        cap=1;
        cost=1;
        add();
    }
    min_cost_flow(s,t,INF);
    //printf("%d %d\n",flow,res);
    printf("%d\n",flow);
    return 0;
}

 

洛谷上的居然要求出是哪些边。

那就根据自己丰富的编程经验瞎搞一发。

#include<bits/stdc++.h>
#define MAXN_ 5050
#define INF 0x3f3f3f3f
#define P pair<int,int>
using namespace std;
struct edge {
    int to,cap,cost,rev;
};
int n,m,flow,s,t,cap,res,cost,from,to,h[MAXN_];
std::vector<edge> G[MAXN_];
int dist[MAXN_],prevv[MAXN_],preve[MAXN_]; // 前驱节点和对应边
inline void add() {
    G[from].push_back((edge) {
        to,cap,cost,(int)G[to].size()
    });
    G[to].push_back((edge) {
        from,0,-cost,(int)G[from].size()-1
    });
} // 在vector 之中找到边的位置所在!
inline int read() {
    int x=0;
    char c=getchar();
    bool flag=0;
    while(c<'0'||c>'9') {
        if(c=='-')
            flag=1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
        x=(x<<3)+(x<<1)+c-'0';
        c=getchar();
    }
    return flag?-x:x;
}
inline void min_cost_flow(int s,int t,int f) {
    fill(h+1,h+1+n,0);
    while(f > 0) {
        priority_queue<P,vector<P>, greater<P> > D;
        memset(dist,INF,sizeof dist);
        dist[s] = 0;
        D.push(P(0,s));
        while(!D.empty()) {
            P now = D.top();
            D.pop();
            if(dist[now.second] < now.first)
                continue;
            int v = now.second;
            for(int i=0; i<(int)G[v].size(); ++i) {
                edge &e = G[v][i];
                if(e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) {
                    dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
                    prevv[e.to] = v;
                    preve[e.to] = i;
                    D.push(P(dist[e.to],e.to));
                }
            }
        }
        // 无法增广 , 就是找到了答案了!
        if(dist[t] == INF)
            break;
        for(int i=1; i<=n; ++i)
            h[i] += dist[i];
        int d = f;
        for(int v = t; v != s; v = prevv[v])
            d = min(d,G[prevv[v]][preve[v]].cap);
        f -= d;
        flow += d;
        res += d * h[t];
        for(int v=t; v!=s; v=prevv[v]) {
            edge &e = G[prevv[v]][preve[v]];
            e.cap -= d;
            G[v][e.rev].cap += d;
        }
    }
}
int main() {
    int n1,n;
    /*1~n1 英国 n1~n 外国*/
    scanf("%d",&n1);
    scanf("%d",&n);
    n+=n1;

    //n = read();
    //m = read();
    //s = read();
    //t = read();
    s=0;
    t=n+1;

    int cnt=0;
    while(1) {
        from = read();
        to = read();
        if(from==-1&&to==-1)
            break;
        //cap = read();
        //cost = read();
        /*手动设置容量和费用为1*/
        cap=1;
        cost=1;
        add();
        cnt+=2;
    }

    /*手动添加超级源点和超级汇点*/
    for(int i=1;i<=n1;i++){
        from=s;
        to=i;
        cap=1;
        cost=1;
        add();
        cnt+=2;
    }

    for(int i=n1+1;i<=n;i++){
        from=i;
        to=t;
        cap=1;
        cost=1;
        add();
        cnt+=2;
    }


    vector<pair<int,int> >ans;
    min_cost_flow(s,t,INF);
    if(flow){
        for(int i=1;i<=n1;i++){
            for(auto j:G[i]){
                if(j.to!=s&&j.cap==0){
                    ans.push_back({i,j.to});
                }
            }
        }

        printf("%d\n",ans.size());
        for(auto i:ans){
            printf("%d %d\n",i.first,i.second);
        }
    }
    else{
        printf("No Solution!\n");
    }

    return 0;
}

 

posted @ 2019-03-28 22:46  韵意  阅读(201)  评论(0编辑  收藏  举报