zoukankan      html  css  js  c++  java
  • [网络流24题] 最小路径覆盖问题(匈牙利 最大流)

    题目链接

    定理: 最小路径覆盖数=|G|-二分图最大匹配数

    所以匈牙利算法就来了,内置匹配,简单易上手

    #include <bits/stdc++.h>
    const int maxn = 310;
    using namespace std;
    typedef long long ll;
    
    vector<int> maps[maxn];
    int pipei[maxn], n, m;
    bool mark[maxn];
    int in[maxn], son[maxn];
    
    bool dfs(int u) //找增广路径,匹配
    {
        for (int i = 0, len = maps[u].size(); i < len; i++){
            int v = maps[u][i];
            if (!mark[v]){
                mark[v] = true;
                if (!pipei[v] || dfs(pipei[v])){
                    pipei[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < m; i++){
            int a, b;
            scanf("%d%d", &a, &b);
            maps[a].push_back(n + b);   //建图
        }
        int ans = 0;
        for (int i = 1; i <= n; i++){
            memset(mark, false, sizeof(mark));
            if (dfs(i))
                ans++;
        }
        for (int i = n + 1; i <= 2 * n; i++){
            if (pipei[i]){
                int u = pipei[i], v = i - n;
                son[u] = v; //u --> v
                in[v]++;    //入度
            }
        }
        for (int i = 1; i <= n; i++){   //输出答案
            if (in[i] == 0){
                int u = i;
                printf("%d", u);
                while ((u = son[u]))
                    printf(" %d", u);
                printf("
    ");
            }
        }
        printf("%d
    ", n - ans); //最小路径覆盖数=|G|-二分图最大匹配数
        getchar();
        getchar();
        return 0;
    }
    

    好吧,从二分图,入手用匈牙利算法,好像就是个模板题了

    最大流:用最大流的话,主要还是建图,还有反向弧为满流,就是匹配边

    #include <bits/stdc++.h>
    const int maxn = 160;
    const int emax = 6000 * 3;
    const int inf = 0x3f3f3f3f;
    using namespace std;
    typedef long long ll;
    
    struct note{
        int u, v, w;
        int next;
    } e[emax];
    int head[maxn * 2], cnt;
    int level[maxn * 2], son[maxn], in[maxn];
    int n, m, s, t;
    
    void add(int u, int v, int w){
        e[cnt].u = u, e[cnt].v = v, e[cnt].w = w;
        e[cnt].next = head[u], head[u] = cnt++; //正向弧
    
        e[cnt].u = v, e[cnt].v = u, e[cnt].w = 0;
        e[cnt].next = head[v], head[v] = cnt++; //反向弧
    }
    
    bool bfs(){
        memset(level, -1, sizeof(level));
        level[s] = 1;
        queue<int> q;
        q.push(s);
        while (!q.empty()){
            int u = q.front();
            q.pop();
            for (int i = head[u]; ~i; i = e[i].next){
                int v = e[i].v;
                if (e[i].w > 0 && level[v] == -1){
                    level[v] = level[u] + 1;
                    q.push(v);
                }
            }
        }
        return level[t] != -1;
    }
    
    int dfs(int u, int delta){
        if (u == t)
            return delta;
        int flow = 0;
        for (int i = head[u]; ~i; i = e[i].next){
            int v = e[i].v;
            if (e[i].w > 0 && level[u] + 1 == level[v]){
                int tmp = dfs(v, min(delta - flow, e[i].w));
                e[i].w -= tmp;
                e[i ^ 1].w += tmp;
                flow += tmp;
            }
        }
        if (flow == inf)
            level[u] = -1;
        return flow;
    }
    
    int Dinic()
    {
        int maxflow = 0, tmp;
        while (bfs()){
            while ((tmp = dfs(s, inf)))
                maxflow += tmp;
        }
        return maxflow;
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        s = 0, t = 2 * n + 1;
        memset(head, -1, sizeof(head));
        for (int i = 0; i < m; i++){
            int a, b;
            scanf("%d%d", &a, &b);
            add(a, b + n, 1);   //建边
        }
        for (int i = 1; i <= n; i++)
            add(s, i, 1);   //建边
        for (int i = n + 1; i <= 2 * n; i++)
            add(i, t, 1);   //建边
    
        int ans = Dinic();
        for (int i = 0; i < cnt; i += 2)
        {
            if (e[i].u == s || e[i ^ 1].u == t)
                continue;
            if (e[i ^ 1].w){ //反向弧
                son[e[i].u] = e[i].v - n;
                in[e[i].v - n]++;
            }
        }
        for (int i = 1; i <= n; i++){
            if (in[i] == 0){
                int u = i;
                printf("%d", u);
                while ((u = son[u]))
                    printf(" %d", u);
                printf("
    ");
            }
        }
        printf("%d
    ", n - ans);
        return 0;
    }
    

    好吧,其实如果,做过类似,最大流去解决二分图匹配的话,又变成模板题了

  • 相关阅读:
    Apache Commons Fileupload 反序列化漏洞分析
    Linux下安装python3.6
    使用salt-stack指定IP添加系统用户为root的权限
    virt-install创建虚拟机并制作成模板
    virsh console 登录CentOS7系统
    Cobbler本机使用VM装机配置方法
    Cobbler自动化部署
    调用python脚本报错/usr/bin/env: python : No such file or directory
    启动keepalived报错(VI_1): received an invalid passwd!
    rsync+sersync实现数据实时同步
  • 原文地址:https://www.cnblogs.com/jizhihong/p/13337350.html
Copyright © 2011-2022 走看看