zoukankan      html  css  js  c++  java
  • 【网络流24题】【洛谷P2764】最小路径覆盖问题【网络流】

    题目大意:

    题目链接:https://www.luogu.org/problemnew/show/P2764

    给定有向图G=(V,E)G=(V,E)。设PPGG的一个简单路(顶点不相交)的集合。如果VV中每个定点恰好在PP的一条路上,则称PPGG的一个路径覆盖。PP中路径可以从VV的任何一个定点开始,长度也是任意的,特别地,可以为00GG的最小路径覆盖是GG所含路径条数最少的路径覆盖.设计一个有效算法求一个GAP ext{GAP}(有向无环图)GG的最小路径覆盖。


    思路:

    由于题目中要求任意一个点都必须正好走一次,所以这肯定是要拆点的,把每个点拆成x1,x2x_1,x_2
    对于GAPGAP中每一条边(u,v)(u,v),我们建边(u2,v)(u_2,v),流量为1。这样就限制了每一条边只能走一次。
    然后将源点连向x2(x[1,n])x_2(xin [1,n])x1(x[1,n])x_1(xin [1,n])连向汇点,跑最大流,就得到了最多可以合并几条道路。因为流一次就相当于合并了一条道路。
    那么最小路径覆盖就是 nn-最大流 了。
    输出方案的话可以利用残余流量,递归输出方案。


    代码:

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=100010,Inf=1e9;
    int n,m,S,T,tot=1,maxflow,head[N],dep[N],cur[N];
    bool vis[N];
    
    struct edge
    {
        int from,to,flow,next;
    }e[N];
    
    void add(int from,int to,int flow)
    {
        e[++tot].to=to;
        e[tot].flow=flow;
        e[tot].next=head[from];
        head[from]=tot;
    }
    
    bool bfs()
    {
        memcpy(cur,head,sizeof(cur));
        memset(dep,0x3f3f3f3f,sizeof(dep));
        queue<int> q;
        q.push(S);
        dep[S]=1;
        while (q.size())
        {
            int u=q.front(),v;
            q.pop();
            for (int i=head[u];~i;i=e[i].next)
            {
                v=e[i].to;
                if (dep[v]>dep[u]+1&&e[i].flow)
                {
                    dep[v]=dep[u]+1;
                    q.push(v);
                }
            }
        }
        return dep[T]<Inf;
    }
    
    int dfs(int x,int flow)
    {
        int low=0;
        if (x==T)
        {
            maxflow+=flow;
            return flow;
        }
        int used=0;
        for (int i=cur[x];~i;i=e[i].next)
        {
            int y=e[i].to;
            cur[x]=i;
            if (dep[y]==dep[x]+1&&e[i].flow)
            {
                low=dfs(y,min(e[i].flow,flow-used));
                if (low)
                {
                    used+=low;
                    e[i].flow-=low;
                    e[i^1].flow+=low;
                    if (used==flow) break;
                }
            }
        }
        return used;
    }
    
    void dinic()
    {
        while (bfs())
            dfs(S,Inf);
    }
    
    void find(int x)
    {
        vis[x-n]=1;
        printf("%d ",x-n);
        for (int i=head[x];~i;i=e[i].next)
        {
            int y=e[i].to;
            if (!e[i].flow && y!=x-n && !vis[y])
            {
                find(y+n);
                return;
            }
        }
    }
    
    int main()
    {
        memset(head,-1,sizeof(head));
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x+n,y,1);
            add(y,x+n,0);
        }
        S=N-1; T=N-2;
        for (int i=1;i<=n;i++)
        {
            add(S,i+n,1);
            add(i+n,S,0);
            add(i,T,1);
            add(T,i,0);
        }
        dinic();
        vis[S]=vis[T]=1;
        for (int i=1;i<=n;i++)
            if (!vis[i])
            {
                find(i+n);
                putchar(10);
            }
        printf("%d
    ",n-maxflow);
        return 0;
    }
    
  • 相关阅读:
    Android Handler主线程和一般线程通信的应用分析
    在java中string为什么要设计成final的
    Java中有几种创建对象的方式
    String和StringBuilder、StringBuffer的区别
    正确的二分查找实现
    SSH编写程序中文乱码解决
    lamda表达式
    kmp算法核心代码
    简洁清晰的quicksort核心代码
    [趣题]生成多个质数的幂积序列
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998139.html
Copyright © 2011-2022 走看看