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

    题意:

    戳这里

    分析:

    模板题

    题意转化一下,(ans=总点数-最大边数=总点数-最大流)

    我们把每一个点拆成入点和出点两部分,原点向每一个入点连一条边,每一个出点向汇点连一条边,对于原图上存在的一条边 (x o y)(x) 的入点向 (y) 的出点连一条边,这些边的流量都是 (1) 这样跑出来的最大流就是原图上的最大边数

    正确性证明:

    按照这样的方式建图,每一个点至多和一个点匹配上,而每一个点和另一个点匹配上的时候最大流会增加 (1) 这样最大流就等价于匹配的点对数 (=) 图上最大边数

    另外这个题还很恶心的要输出方案,看题解后发现,可以通过枚举边,将流量为 (0) 的正边,(to) 并到 (frm) 的并查集里,这样每一个并查集的代表元就是路径的一个起点

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
        int read()
        {
            int x=0,f=1;char ch=getchar();
            while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
            while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
            return x*f;
        }
        
        const int maxn = 305;
        const int maxm = 2e4+5;
        const int inf = 0x3f3f3f3f;
        int head[maxn],dep[maxn],fa[maxn];
        int n,m,ans,cnt=1,st,ed;
        queue<int> q;
    
        struct edge
        {
            int frm,to,nxt,w;
        }e[maxm];
    
        void add_edge(int u,int v,int w)
        {
            e[++cnt].to=v;
            e[cnt].frm=u;
            e[cnt].w=w;
            e[cnt].nxt=head[u];
            head[u]=cnt;
        }
    
        void add(int u,int v,int w)
        {
            add_edge(u,v,w);
    		add_edge(v,u,0);
        }
    	
    	int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    	
        bool bfs()
        {
            for(int i=st;i<=ed;i++) dep[i]=-1;
            dep[st]=0;q.push(st);
            while(!q.empty())
            {
                int u=q.front();q.pop();
                for(int i=head[u];i;i=e[i].nxt)
                {
                    int v=e[i].to;
                    if(e[i].w&&dep[v]==-1)
                    {
                        dep[v]=dep[u]+1;
                        q.push(v);
                    }
                }
            }
            return dep[ed]!=-1;
        }
    
        int dfs(int u,int f)
        {
            if(u==ed) return f;
            int used=0,w;
            for(int i=head[u];i;i=e[i].nxt)
            {
                int v=e[i].to;
                if(e[i].w&&dep[v]==dep[u]+1)
                {
                    w=dfs(v,min(e[i].w,f-used));
                    e[i].w-=w;
                    e[i^1].w+=w;
                    used+=w;
                    if(used==f) return used;
                }
            }
            if(!used) dep[u]=-1;
            return used;
        }
    
        void dinic()
        {
            while(bfs())
            {
                int fl=dfs(st,inf);
                ans-=fl;
            }
        }
        
        void solve(int u)
        {
        	printf("%d ",u);
        	for(int i=head[u];i;i=e[i].nxt)
        	{
        		if(!e[i].w&&e[i].to>n)
        		{
        			solve(e[i].to-n);
        			return ;
    			}
    		}
    	}
        
        void work()
        {
            int a,b;
            n=read();m=read();ans=n;st=0;ed=2*n+1;
            for(int i=1;i<=m;i++)
            {
                a=read();b=read();
                add(a,b+n,1);
            }
            for(int i=1;i<=n;i++) fa[i]=i,add(st,i,1),add(i+n,ed,1);
            dinic();
            for(int i=2;i<=cnt;i++) if(e[i].frm>=1&&e[i].frm<=n&&e[i].to>n&&e[i].to<ed&&e[i].w==0) fa[find(e[i].to-n)]=find(e[i].frm);
    		for(int i=1;i<=n;i++) if(find(i)==i){solve(i);puts("");}
            printf("%d
    ",ans);
        }
    
    }
    
    int main()
    {
        zzc::work();
        return 0;
    }
    
  • 相关阅读:
    strcpy和memcpy的区别(转)
    获得discuz7.2 目录下所有文件,并写到txt
    Lintcode: Majority Number 解题报告
    Lintcode: Fast Power 解题报告
    LeetCode: Pow(x, n) 解题报告
    Lintcode: Minimum Subarray 解题报告
    Lintcode: Subarray Sum 解题报告
    LeetCode: Minimum Depth of Binary Tree 解题报告
    LeetCode: Binary Tree Maximum Path Sum 解题报告
    LeetCode: Binary Tree Postorder Traversal 解题报告
  • 原文地址:https://www.cnblogs.com/youth518/p/14221731.html
Copyright © 2011-2022 走看看