zoukankan      html  css  js  c++  java
  • 【刷题】LOJ 6002 「网络流 24 题」最小路径覆盖

    题目描述

    给定有向图 (G = (V, E)) 。设 (P)(G) 的一个简单路(顶点不相交)的集合。如果 (V) 中每个顶点恰好在 (P) 的一条路上,则称 (P)(G) 的一个路径覆盖。(P) 中路径可以从 (V) 的任何一个顶点开始,长度也是任意的,特别地,可以为 (0)(G) 的最小路径覆盖是 (G) 的所含路径条数最少的路径覆盖。

    设计一个有效算法求一个有向无环图 (G) 的最小路径覆盖。

    输入格式

    (1) 行有 (2) 个正整数 (n)(m)(n) 是给定有向无环图 (G) 的顶点数,(m)(G) 的边数。

    接下来的 (m) 行,每行有 (2) 个正整数 (u)(v) ,表示一条有向边 ((i, j))

    输出格式

    从第 (1) 行开始,每行输出一条路径。

    文件的最后一行是最少路径数。

    样例

    样例输入

    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
    

    样例输出

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

    数据范围与提示

    (1 leq n leq 200, 1 leq m leq 6000)

    题解

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

    源点向所有出点连容量为 (1) 的边,所有入点向汇点连容量为 (1) 的边

    如果原图中有 (u)(v) 的边,那么在 (u) 的出点向 (v) 的入点连容量为 (1) 的边

    那么原点数减去新的二分图中的最大匹配的就是答案

    #include<bits/stdc++.h>
    #define ui unsigned int
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    const int MAXN=200,MAXM=6000,inf=0x3f3f3f3f;
    int e=1,n,m,beg[MAXN<<1],nex[MAXM<<1],to[MAXM<<1],out[MAXM<<1],level[MAXN<<1],vis[MAXM<<1],cur[MAXN<<1],cap[MAXM<<1],nxt[MAXN<<1],clk,s,t,ans;
    std::queue<int> q;
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char ch='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(ch!='')putchar(ch);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline void insert(int x,int y,int z)
    {
    	to[++e]=y;
    	nex[e]=beg[x];
    	out[e]=x;
    	beg[x]=e;
    	cap[e]=z;
    	to[++e]=x;
    	nex[e]=beg[y];
    	out[e]=y;
    	beg[y]=e;
    	cap[e]=0;
    }
    inline bool bfs()
    {
    	memset(level,0,sizeof(level));
    	level[s]=1;
    	q.push(s);
    	while(!q.empty())
    	{
    		int x=q.front();
    		q.pop();
    		for(register int i=beg[x];i;i=nex[i])
    			if(!level[to[i]]&&cap[i])
    			{
    				level[to[i]]=level[x]+1;
    				q.push(to[i]);
    			}
    	}
    	return level[t];
    }
    inline int dfs(int x,int maxflow)
    {
    	if(!maxflow||x==t)return maxflow;
    	vis[x]=clk;
    	int res=0,f;
    	for(register int &i=cur[x];i;i=nex[i])
    		if((vis[x]^vis[to[i]])&&cap[i]&&level[to[i]]==level[x]+1)
    		{
    			f=dfs(to[i],min(maxflow,cap[i]));
    			maxflow-=f;
    			cap[i]-=f;
    			cap[i^1]+=f;
    			res+=f;
    			if(!maxflow)break;
    		}
    	vis[x]=0;
    	return res;
    }
    inline int Dinic()
    {
    	int res=0;
    	while(bfs())clk++,memcpy(cur,beg,sizeof(cur)),res+=dfs(s,inf);
    	return res;
    }
    inline void exdfs(int x)
    {
    	if(!x)return ;
    	vis[x]=1;
    	if(x<=n)write(x,' ');
    	exdfs(nxt[x]);
    }
    int main()
    {
    	read(n);read(m);
    	for(register int i=1;i<=m;++i)
    	{
    		int u,v;
    		read(u);read(v);
    		insert(u,v+n,1);
    	}
    	s=n+n+1,t=s+1;
    	for(register int i=1;i<=n;++i)insert(s,i,1),insert(n+i,t,1);
    	ans=Dinic();
    	memset(vis,0,sizeof(vis));
    	for(register int i=2;i<=(m<<1);i+=2)
    		if(!cap[i])nxt[out[i]]=to[i];
    	for(register int i=1;i<=n;++i)nxt[i+n]=i;
    	for(register int i=1;i<=n;++i)
    		if(!vis[i])exdfs(i),puts("");
    	write(n-ans,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    ArrayList集合封装 类 并通过方法调用
    ArrayList集合的基本操作
    方法的重复定义和重载
    方法间值的传递,二维数组的定义和遍历
    赋值运算,逻辑运算符,引用数据类型
    Javase;jdk的安装调试;基础语法和变量以及基础数据类型
    E-R画图规则和数据库设计的三大范式
    sql多表查询和子查询
    sql约束的使用
    sql表操作的基础语法
  • 原文地址:https://www.cnblogs.com/hongyj/p/9424631.html
Copyright © 2011-2022 走看看