code vs [网络流24题]最小路径覆盖问题

来源:互联网 发布:淘宝联盟使用红包 编辑:程序博客网 时间:2024/06/08 16:14

1904 最小路径覆盖问题

 时间限制: 2 s
 空间限制: 256000 KB
 题目等级 : 大师 Master
题目描述 Description

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

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

输入描述 Input Description

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

输出描述 Output Description

最少路径数。

样例输入 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


题解:

此题的关键是:最小路径覆盖=原图点数-最大匹配

最大独立集=原图点数-最大匹配    

那么最大匹配可以转化为求最大流。那么如何建图呢?拆点。

把每个点拆成两个,一个表示进,一个表示出

#include<iostream>#include<cstdio>#include<cstring>#include<queue>using namespace std;int point[2100],next[2000003],v[2000003],remain[2000003];int deep[2100],cur[2100],n,m,tot;const int inf=1e9;void add(int x,int y,int z){  tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z;  tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;}bool bfs(int s,int t){memset(deep,0x7f,sizeof(deep));for (int i=s;i<=t;i++) cur[i]=point[i];deep[s]=0;queue<int> p;p.push(s);while (!p.empty()) {  int now=p.front(); p.pop();  for (int i=point[now];i!=-1;i=next[i])   if (deep[v[i]]>inf&&remain[i])    deep[v[i]]=deep[now]+1,p.push(v[i]); }return deep[t]<inf;}int dfs(int now,int t,int limit){if (!limit||now==t)  return limit;int flow=0,f;for (int i=cur[now];i!=-1;i=next[i]) { cur[now]=i; if (deep[v[i]]==deep[now]+1&&(f=dfs(v[i],t,min(limit,remain[i]))))  {  flow+=f; limit-=f;  remain[i]-=f; remain[i^1]+=f;  if (!limit) break;  } }return flow;}int dinic(int s,int t){ int ans=0; while (bfs(s,t))  ans+=dfs(s,t,inf); return ans;}int main(){  tot=-1;  memset(point,-1,sizeof(point));  memset(next,-1,sizeof(next));  scanf("%d%d",&n,&m);  for (int i=1;i<=m;i++)   {   int x,y; scanf("%d%d",&x,&y);   add(x,y+n,inf);   }  for (int i=1;i<=n;i++) add(0,i,1);  for (int i=1;i<=n;i++) add(n+i,2*n+1,1);  printf("%d",n-dinic(0,2*n+1));}


0 0
原创粉丝点击