NKOI 1938 最小路径覆盖

【线性规划与网络流24题 3】最小路径覆盖

Time Limit:10000MS  Memory Limit:65536K
Total Submit:35 Accepted:14 
Case Time Limit:1000MS

Description

给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。 
对于给定的给定有向无环图G,编程找出 G的一个最小路径覆盖。 
由于本OJ无Special Judge , 所以只需要输出路径的条数

Input

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

Output

一行,包含一个整数,表示最少路径数

Sample Input

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 

Sample Output

3

Source

感谢 Wo_ai_WangYuan 修改题目并放上数据


网络流模型

我们先将n个点分成x,y两个集合,如果u到v有一条边,就将u放在x集合,v放在y集合

然后就是网络流建图,这里先给出建图方式

设源点为op,汇点为ed,那么op与x集合所有点连一条容量为1的边(即x中的每个点只能用一次)

x集合与y集合中能互相到达的两点连一条容量>=1的边,最后y集合中每一个点与ed连一条容量为1的边(即y中的每个点只能用一次)

这样建图后求出来的最大流就一定是最大匹配数(想一想为什么)

ans=n-最大匹配,如果无匹配,显然要n条路径才能覆盖所有点,两个点匹配意味着将可以把它们用一条路径覆盖,路径数就可以减1

#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=305,inf=1e9;
int n,m, g[maxn][maxn],op,ed;
int dis[maxn],vd[maxn];
int dfs(int u,int flow){    
    if(u==ed)return flow;    
    int v,temp,delta=0;    
    for(v=1;v<=ed;v++)    
        if(g[u][v]&&dis[u]==dis[v]+1){    
            temp=dfs(v,min(flow-delta,g[u][v]));    
            g[u][v]-=temp;    
            g[v][u]+=temp;    
            delta+=temp;    
            if(delta==flow||dis[op]>=ed)return delta;    
        }    
    if(dis[op]>=ed)return delta;    
    vd[dis[u]]--;    
    if(vd[dis[u]]==0)dis[op]=ed;    
    dis[u]++;    
    vd[dis[u]]++;    
    return delta;    
}  
int main(){
	cin>>n>>m;
	int i,j,x,y,ans=0;
	op=n+n+1,ed=op+1;
	for(i=1;i<=m;i++){
		cin>>x>>y;
		g[op][x]=1;
		g[x][y+n]=1;
		g[y+n][ed]=1;
	}
	while(dis[op]<ed)ans+=dfs(op,inf);
	cout<<n-ans;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值