zoukankan      html  css  js  c++  java
  • [网络流24题(1/24)] 最小路径覆盖问题(洛谷P2764)

    传送门

    分析:

    本题的结论是:最小路径覆盖=顶点数-原图的最大匹配数

    证明(逼逼)

    对于$1$对由$1$条边覆盖的点而言,$点数-1=边数$

    倘若对于$n$个由$m$边所覆盖的点而言,则等价于把上述式子归纳,则有:$$n-m=cover$$

    而现在我们需要令$cover$最大化,显然我们必定是要取到尽可能多的符合题意的边数。

    而在题目中,存在着一个点只能被一条边所覆盖,因此,这代表着,对于一个点,只能够有一条入边,同时也只能有一条出边。

    考虑到这个限制,我们考虑将一个点拆成两个点,其中一个点代表入点,另一个点代表出点,根据原图的关系$u o v$,将当前$u$的出点连向下一个点$v$的入点,且边的容量为$1$。

    而这样建出来的图,则可以满足一个点只能被一条边入,一条边出的限制。

    之后我们发现,我们现在所连出来的的一张图是二分图,故我们可以直接建立超级源点和超级汇点,并在这张图上跑最大流即可以求出最大的边数$m$。因此最终的答案即为 $n-m$。

    同时这个题中需要我们求出路径数。而对于这个,我们可以通过这张图的残量网络去求解。我们遍历每一个点,如果发现某一个点的当前容量为$0$,则不断延申这条边直到终点。而又因为在这张图中每条边的容量上限为$1$,故一条全部为$0$的路径必定为答案。而因为这样的过程中,最多遍历每个点$1$次,故时间复杂度为$mathcal{O(n)}$

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1005;
    const int maxm=10005;
    const int inf=0x3f3f3f3f;
    struct Node{
        int to,val,next;
    }q[maxm<<1];
    int head[maxn],cnt=0,dep[maxn],cur[maxn],vis[maxn];
    int tag[maxn];
    int sp,ep,maxflow;
    void init(){
        memset(head,-1,sizeof(head));
        cnt=2,maxflow=0;
    }
    void add_edge(int from,int to,int val){
        q[cnt].to=to;
        q[cnt].val=val;
        q[cnt].next=head[from];
        head[from]=cnt++;
    
        q[cnt].to=from;
        q[cnt].val=0;
        q[cnt].next=head[to];
        head[to]=cnt++;
    }
    bool bfs(int n){
        for(int i=0;i<=n;i++){
            cur[i]=head[i],dep[i]=0x3f3f3f3f;
            vis[i]=0;
        }
        dep[sp]=0;
        queue<int>que;
        que.push(sp);
        while(!que.empty()){
            int x=que.front();
            que.pop();
            vis[x]=0;
            for(int i=head[x];i!=-1;i=q[i].next){
                int to=q[i].to;
                if(dep[to]>dep[x]+1&&q[i].val){
                    dep[to]=dep[x]+1;
                    if(!vis[to]){
                        que.push(to);
                        vis[to]=1;
                    }
                }
            }
        }
        if(dep[ep]!=inf) return true;
        else return false;
    }
    int dfs(int x,int flow){
        int rlow=0;
        if(x==ep){
            maxflow+=flow;
            return flow;
        }
        int used=0;
        for(int i=cur[x];i!=-1;i=q[i].next){
            cur[x]=i;
            int to=q[i].to;
            if(q[i].val&&dep[to]==dep[x]+1){
                if(rlow=dfs(to,min(flow-used,q[i].val))){
                    used+=rlow;
                    q[i].val-=rlow;
                    q[i^1].val+=rlow;
                    if(used==flow) break;
                }
            }
        }
        return used;
    }
    int dinic(int n){
        while(bfs(n)){
            dfs(sp,inf);
        }
        return maxflow;
    }
    void Find_Path(int n){
        for(int i=1;i<=n;i++){
            if(!tag[i]){
                int x=i,flag=0,to=0;
                while(x!=ep){
                    for(int j=head[x];j!=-1;j=q[j].next){
                        if(q[j].val) continue;
                        to=q[j].to;
                        printf("%d ",x);
                        tag[x]=1,flag=1;
                        if(to==sp) break;
                        x=to-n;
                        break;
                    }
                    if(to==sp) break;
                }
                if(flag) puts("");
            }
        }
    }
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        sp=0,ep=2*n+1;
        init();
        for(int i=0;i<m;i++){
            int from,to;
            scanf("%d%d",&from,&to);
            add_edge(from,to+n,1);
        }
        for(int i=1;i<=n;i++){
            add_edge(sp,i,1);
            add_edge(i+n,ep,1);
        }
        int res=n-dinic(ep);
        Find_Path(n);
        printf("%d
    ",res);
        return 0;
    }
    
  • 相关阅读:
    C#开发微信门户及应用(7)-微信多客服功能及开发集成
    C#开发微信门户及应用(6)--微信门户菜单的管理操作
    使用Json.NET来序列化所需的数据
    Winform开发框架里面使用事务操作的原理及介绍
    C#开发微信门户及应用(5)--用户分组信息管理
    C#开发微信门户及应用(4)--关注用户列表及详细信息管理
    基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据
    基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面
    基于MVC4+EasyUI的Web开发框架经验总结(1)-利用jQuery Tags Input 插件显示选择记录
    如何在应用系统中实现数据权限的控制功能
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007132.html
Copyright © 2011-2022 走看看