• 二分图最大匹配


    匈牙利算法,通过反复寻找增广路的方法求最大匹配。

     1 const int MAXV = 1001;
     2 int V;                //顶点数
     3 vector<int> G[MAXV];  //图的邻接表表示
     4 int match[MAXV];      //所匹配的定点
     5 bool used[MAXV];      // DFS中用到的访问标记
     6 
     7 //添加无向边,注意顶点编号从0开始
     8 void add_edge(int u, int v) {
     9     G[u].push_back(v);
    10     G[v].push_back(u);
    11 }
    12 
    13 //通过DFS寻找增广路
    14 bool dfs(int v) {
    15     used[v] = true;
    16     for (int i = 0; i < G[v].size(); i++) {
    17         int u = G[v][i], w = match[u];
    18         if (w < 0 || !used[w] && dfs(w)) {
    19             match[v] = u;
    20             match[u] = v;
    21             return true;
    22         }
    23     }
    24     return false;
    25 }
    26 
    27 //二分图最大匹配,返回最大匹配数
    28 int Bipartite_Matching() {
    29     int res = 0;
    30     memset(match, -1, sizeof(match));
    31     for (int v = 0; v < V; v++) {
    32         if (match[v] < 0) {
    33             memset(used, 0, sizeof(used));
    34             if (dfs(v)) {
    35                 res++;
    36             }
    37         }
    38     }
    39     return res;
    40 }

    POJ3041

    题意:

     在一个N*N的网格上有K个小行星,小行星的位置是($R_i$, $C_i$),有武器一次可以摧毁或一列的小行星,问最少几次使用武器可以将小行星全部摧毁。

    解法:

    把光束(横、纵两种)当作顶点,把小行星的位置当作边。问题就是选若干个点(光束)覆盖所有的边,这是最小顶点覆盖(任意边都有只少一个顶点被涵盖),等效于最大匹配。

    横纵两种光束是二分图,所以直接二分最大匹配即可。

    代码如下:

     1 const int MAXV = 1001;
     2 int V;                //顶点数
     3 vector<int> G[MAXV];  //图的邻接表表示
     4 int match[MAXV];      //所匹配的定点
     5 bool used[MAXV];      // DFS中用到的访问标记
     6 
     7 //添加无向边,注意顶点编号从0开始
     8 void add_edge(int u, int v) {
     9     G[u].push_back(v);
    10     G[v].push_back(u);
    11 }
    12 
    13 //通过DFS寻找增广路
    14 bool dfs(int v) {
    15     used[v] = true;
    16     for (int i = 0; i < G[v].size(); i++) {
    17         int u = G[v][i], w = match[u];
    18         if (w < 0 || !used[w] && dfs(w)) {
    19             match[v] = u;
    20             match[u] = v;
    21             return true;
    22         }
    23     }
    24     return false;
    25 }
    26 
    27 //二分图最大匹配,返回最大匹配数
    28 int Bipartite_Matching() {
    29     int res = 0;
    30     memset(match, -1, sizeof(match));
    31     for (int v = 0; v < V; v++) {
    32         if (match[v] < 0) {
    33             memset(used, 0, sizeof(used));
    34             if (dfs(v)) {
    35                 res++;
    36             }
    37         }
    38     }
    39     return res;
    40 }
    41 
    42 const int MAXK = 10000 + 5;
    43 int N, K;
    44 int R[MAXK], C[MAXK];
    45 
    46 int main() {
    47 #ifndef ONLINE_JUDGE
    48     freopen("input.txt", "r", stdin);
    49 #endif  // !ONLINE_JUDGE
    50     N = READ(), K = READ();
    51     REP(i, 1, K) {
    52         int R = READ(), C = READ();
    53         add_edge(R - 1, C + N - 1);
    54     }
    55     V = N + N;
    56     printf("%d
    ", Bipartite_Matching());
    57     return 0;
    58 }
  • 相关阅读:
    (八)CXF之用spring添加拦截器
    (七)CXF之与spring整合发布web服务
    (六)CXF之自定义拦截器
    借鉴mini2440的usb-wifi工具集在Beagleboard上移植无线网卡
    ubuntu设置网络
    mysql优化学习
    java日期转化
    Navicat使用
    (转载)windows下mysql忘记密码
    java读取文件乱码
  • 原文地址:https://www.cnblogs.com/romaLzhih/p/9489795.html
Copyright © 2020-2023  润新知