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

    (color{#0066ff}{题目描述})

    给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。提示:设V={1,2,.... ,n},构造网络G1=(V1,E1)如下:

    每条边的容量均为1。求网络G1的( 0 x , 0 y )最大流。

    对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。

    (color{#0066ff}{输入格式})

    文件第1 行有2个正整数n和m。n是给定有向无环图G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数i和j,表示一条有向边(i,j)。

    (color{#0066ff}{输出格式})

    从第1 行开始,每行输出一条路径。文件的最后一行是最少路径数。

    (color{#0066ff}{输入样例})

    11 12
    1 2
    1 3
    1 4
    2 5
    3 6
    4 7
    5 8
    6 9
    7 10
    8 11
    9 11
    10 11
    

    (color{#0066ff}{输出样例})

    1 4 7 10 11
    2 5 8
    3 6 9
    3
    

    (color{#0066ff}{数据范围与提示})

    有spj

    (color{#0066ff}{题解})

    最小路径覆盖=总点数-最大匹配/最大流

    拆点,每个点拆成出点和入点

    原图中(i o j),则将i的出点和j的入点连边

    最后暴力跳就行

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define _ 0
    #define LL long long
    inline LL in()
    {
    	LL x=0,f=1; char ch;
    	while(!isdigit(ch=getchar()))(ch=='-')&&(f=-f);
    	while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    	return x*f;
    }
    const int inf=0x7fffffff;
    const int max=1050;
    int n,m,s,t,cnt=1;
    struct node
    {
    	int to,nxt,dis;
    	node(int to=0,int nxt=0,int dis=0):to(to),nxt(nxt),dis(dis){}
    }e[120000]; 
    int head[max],cur[max],dep[max];
    std::queue<int> q;
    bool vis[max];
    inline void add(int from,int to,int dis)
    {
    	e[++cnt]=node(to,head[from],dis);
    	head[from]=cnt;
    }
    inline bool bfs()
    {
    	for(int i=s;i<=t;i++) cur[i]=head[i],dep[i]=0;
    	dep[s]=1;
    	q.push(s);
    	while(!q.empty())
    	{
    		int tp=q.front(); q.pop();
    		for(int i=head[tp];i;i=e[i].nxt)
    		{
    			int go=e[i].to;
    			if(!dep[go]&&e[i].dis>0) 
    			{
    				dep[go]=dep[tp]+1;
    				q.push(go);
    			}
    		}
    	}
    	return dep[t];
    }
    inline int dfs(int x,int change)
    {
    	if(x==t||!change) return change;
    	int flow=0,ls;
    	for(int i=cur[x];i;i=e[i].nxt)
    	{
    		int go=e[i].to;
    		cur[x]=i;
    		if(dep[go]==dep[x]+1&&(ls=dfs(go,std::min(e[i].dis,change))))
    		{
    			change-=ls;
    			flow+=ls;
    			e[i].dis-=ls;
    			e[i^1].dis+=ls;
    			if(!change) break;
    		}
    	}
    	return flow;
    }
    inline int dinic()
    {
    	int flow=0;
    	while(bfs()) flow+=dfs(s,inf);
    	return flow;
    }
    inline int nxt(int x)
    {
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int go=e[i].to;
    		if(go>=n+1&&go<=n+n&&e[i].dis!=inf) return go-n;
    	}
    	return 0;
    }
    inline void print()
    {
    	int ans=dinic();
    	vis[0]=true;
    	for(int i=1;i<=n;i++)
    	{
    		if(!vis[i])
    		{
    			for(int o=i;!vis[o];o=nxt(o))
    			{
    				vis[o]=true;
    				printf("%d ",o);
    			}
    			putchar('
    ');
    		}
    	}
    	printf("%d",n-ans);
    }
    int main()
    {
    	n=in(),m=in();
    	s=0,t=(n<<1)+1;
    	int x,y;
    	for(int i=1;i<=m;i++) x=in(),y=in(),add(x,y+n,inf),add(y+n,x,0);
    	for(int i=1;i<=n;i++) add(s,i,1),add(i,s,0),add(i+n,t,1),add(t,i+n,0);
    	print();
    	return 0;
    }
    
  • 相关阅读:
    [Project Euler 603]Substring sums of prime concatenations 题解
    [Project Euler 521]Smallest prime factor 题解
    [Project Euler 520]Simbers 题解
    [Project Euler 517]A real recursion 题解
    省选刷题计划
    [十二省联考2019]春节十二响
    导航
    有用的网址
    [ZJOI2019]线段树
    [十二省联考2019]皮配
  • 原文地址:https://www.cnblogs.com/olinr/p/10102139.html
Copyright © 2011-2022 走看看