线性规划与网络流24题の1 飞行员配对方案问题(最大匹配)

来源:互联网 发布:鳄鱼毒品知乎 编辑:程序博客网 时间:2024/05/01 13:52

最大流水题。就二分图最大匹配数。

输出方案不唯一...=。=,所以在没有special judge的OJ会出错(也是实在没想明白标程的解是怎么输出的。。。

//#pragma comment(linker,"/STACK:1024000000,1024000000")#include <map>#include <set>#include <cmath>#include <queue>#include <stack>#include <cstdio>#include <string>#include <vector>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef double DB;typedef long long ll;typedef pair<int, int> PII;#define pb push_back#define MP make_pair#define lson l, m, rt << 1#define rson m + 1, r, rt << 1 | 1const DB eps = 1e-6;const int inf = ~0U>>1;const ll INF = 0x3f3f3f3f3f3f3f3f;const int mod = 1000000007;const int maxn = 40000 + 10;///init是初始化要在加边之前初始化,然后调用max_flow(顶点数,边数,源点, 汇点)const int maxv = 40000 + 10;///顶点个数const int maxe = 1000000 + 10;///边数int c[maxe];struct node{    int v, cap, next;}edge[maxe];int head[maxv], cnt;int n;///n是节点个数,m是边数int st, ed;///st是源点,ed是汇点int gap[maxv], h[maxv];void addedge(int u, int v, ll w){///有向图加边    edge[cnt].v = v; edge[cnt].cap = w; edge[cnt].next = head[u]; head[u] = cnt++;///正向边    edge[cnt].v = u; edge[cnt].cap = 0; edge[cnt].next = head[v]; head[v] = cnt++;///反向边}int dfs(int x, int cost){    if(x == ed) return cost; ///当前节点是汇点,直接返回cost    int can = cost, d, minh = n - 1;    for(int i=head[x]; ~i; i=edge[i].next){        int v = edge[i].v, w = edge[i].cap;        if(w > 0){///如果这条边的容量大于0            if(h[v] + 1 == h[x]){///如果这是允许弧                if(can > w) d = w;///如果当前弧的容量小于之前可增广的容量                else d = can;                d = dfs(v, d);///从v开始可增广的容量为d                ///更新弧的容量和可增广的容量                edge[i].cap -= d;                edge[i ^ 1].cap += d;                can -= d;                if(h[st] >= n) return cost - can;                if(!can) break;///不能再继续增广            }            if(h[v] < minh) minh = h[v];///更新最小标号        }    }    if(can == cost){///如果没有增广...GAP        gap[h[x]]--;        if(gap[h[x]] == 0) h[st] = n;///存在断层,没有增广路了        h[x] = minh + 1;///重新标记,保证下次再访问的时候有流量        gap[h[x]]++;    }    return cost - can;///在这个点之前可以增广的 - 访问这个点之后可以增广的 = 在这个点增广的容量}int max_flow(int N){///SAP+GAP优化    n = N;//m = M;    for(int i=0; i<cnt; i++) c[i] = edge[i].cap;    memset(h, 0, sizeof(h));///h[i]表示i节点的标号    memset(gap, 0, sizeof(gap));///gap[i]表示标号为i的节点个数    gap[0] = n;///初始有n个节点标号为0    int ret = 0;    while(h[st] < n){        ret += dfs(st, inf);    }    return ret;}void init(int source, int sink){    memset(head, -1, sizeof(head)); cnt = 0;    st = source; ed = sink;}///求割集bool vis[maxn];void Dfs(int x){    vis[x] = true;    for(int i=head[x]; ~i; i=edge[i].next){        if(edge[i].cap > 0 && !vis[edge[i].v]) Dfs(edge[i].v);    }}int N, M;int main(){    cin >> M >> N;    init(0, N + 1);    for(int i=1; i<=M; i++)        addedge(st, i, 1);    for(int i=M+1; i<=N; i++)        addedge(i, ed, 1);    int u, v;    while(scanf("%d%d", &u, &v) == 2){        if(u == -1 && v == -1) break;        addedge(u, v, 1);    }    int ans =  max_flow(N + 2);    if(ans == 0) {puts("No Solution!"); return 0;}    cout << ans << endl;    for(int i=head[st]; ~i; i=edge[i].next)    if(edge[i].cap == 0){        int u = edge[i].v;        for(int j=head[u]; ~j; j=edge[j].next)        if(edge[j].v != st && edge[j].cap == 0){            printf("%d %d\n", u, edge[j].v);            break;        }    }    return 0;}


0 0
原创粉丝点击