二分图的匹配

来源:互联网 发布:gamemaker 源码 编辑:程序博客网 时间:2024/05/14 11:04

方法一:利用网络流新增源点和汇点的方法

#include <iostream>#include <vector>#include <climits>#include <cstring>using namespace std;const int MAX_V = 1100;struct edge{int to, cap, rev;};   ///邻接表表示,点,容量,反向边vector<edge> G[MAX_V];bool used[MAX_V];/// 贪心策略: 1.找到f < c 或者 f > 0 的边,寻找路径 2.不存在路径则结束,若存在路径则返回1继续寻找void add_edge(int from, int to, int cap) {    ///添加边    G[from].push_back((edge){to, cap, G[to].size()});    G[to].push_back((edge){from, 0, G[from].size() - 1});}int dfs(int v, int t, int f) {    if(v == t) return f;    used[v] = true;    for(int i = 0; i < G[v].size(); ++i) {        edge &e = G[v][i];        if(!used[e.to] && e.cap > 0) {            int d = dfs(e.to, t, min(f, e.cap));            if(d > 0) {                e.cap -= d;    ///该边减小容量                G[e.to][e.rev].cap += d;   ///反向边增加容量                return d;            }        }    }}int max_flow(int s, int t) {    int flow = 0;    for(;;) {        memset(used, 0, sizeof(used));        int f = dfs(s, t, INT_MAX);        if(f == 0) return flow;        flow += f;    }}/// 0 ~ N - 1 计算机对应的顶点/// N ~ N + K - 1 任务对应的顶点int N, K;int can[MAX_V][MAX_V];void solve() {    int s = N + K, t = s + 1;  ///s 为新的源点,t为新的汇点    for(int i = 0; i < N; ++i) {        add_edge(s, i, 1);    }    for(int i = 0; i < K; ++i) {        add_edge(N + i, t, 1);    }    for(int i = 0; i < N; ++i) {        for(int j = 0; j < K; ++j) {            if(can[i][j]) {                add_edge(i, N + j, 1);            }        }    }    cout << max_flow(s, t) << endl;}int main(){    cin >> N >> K;    int k;    cin >> k;    memset(can, 0, sizeof(can));    for(int i = 0; i < k; ++i) {        int p, q;        cin >> p >> q;        can[p][q] = 1;        can[q][p] = 1;    }    solve();    return 0;}/*3 350 00 11 01 22 1*/

方法二:贪心法进行增广路

#include <iostream>#include <vector>#include <cstring>const int MAX_V = 1100;const int INF = INT_MAX;using namespace std;int V;vector<int> G[MAX_V];int match[MAX_V];bool used[MAX_V];///贪心策略:依次遍历每个点,进行增广路径,规则为:未匹配,或已经匹配但未进行遍历的点。void add_edge(int u, int v){    G[u].push_back(v);    G[v].push_back(u);}bool dfs(int v){    used[v] = true;    for(int i = 0; i < G[v].size(); ++i) {        int u = G[v][i], w = match[u];        if(w < 0 || !used[w] && dfs(w)) {  ///该处为该贪心算法关键点            match[v] = u;            match[u] = v;            return true;        }    }    return false;}int bipartite_matching(){    int res = 0;    memset(match, -1, sizeof(match));    for(int v = 0; v < V; v++) {        if(match[v] < 0) {            memset(used, 0, sizeof(used));            if(dfs(v)) {                res++;            }        }    }    return res;}int main(){    int s, x, y;    cin >> s >> V;    for(int i = 0; i < s; ++i) {        cin >> x >> y;        add_edge(x, y);    }    cout << bipartite_matching() << endl;    return 0;}/*5 60 30 41 31 52 4*/


0 0
原创粉丝点击