POJ 2594 (传递闭包 + 最小路径覆盖)
Posted absofuckinglutely
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 2594 (传递闭包 + 最小路径覆盖)相关的知识,希望对你有一定的参考价值。
题目大意:给你 1~N 个点, M 条有向边。问你最少需要多少个机器人,让它们走完所有节点,不同的机器人可以走过同样的一条路,图保证为 DAG。
很明显是 最小可相交路径覆盖 问题。要先通过闭包建图后,再当作 最小不可交路径覆盖 问题 求解即可。
原因:
与 最小不可交路径覆盖 问题不同的是,两个机器人可以走相同的边,在最小覆盖的基础上如果还要走过相同的边,那么说明后一个机器人到达某一个未被走过的节点时,必须要经过某一条路,即已经走过的这条路。
比如,前一个机器人已经走了 A-->B-->C ,而后一个机器人为了到 D 点,走 A-->B-->D ,则重复的路为 A-->B 。如果我们用闭包传递后,在 A 能到达的所有节点上进行建图的话,那么 A-->B 是单独的一条, A-->C 与 A-->D 也是单独的一条,这样就使得 A 到 D 的话就不需要再经过 A-->B 了,就变成不可交的了。
同样,对于 A-->B 的点,建立 Ax-->By,变成二分图即可。(最小不可交路径覆盖问题)
代码如下:
#include<iostream> #include<algorithm> #include<string.h> #define maxn 508 using namespace std; int n,m,cnt; int head[maxn],c[maxn]; bool flag[maxn][maxn],vis[maxn]; struct Edge int to; int next; edge[maxn*maxn*2];4387596 inline void add(int u,int v) edge[++cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt; return; void floyd() for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(flag[i][k]&&flag[k][j]) flag[i][j]=true,add(i,j); return; int dfs(int u) for(int i=head[u];i;i=edge[i].next) int v=edge[i].to; if(vis[v]) continue; vis[v]=true; if(c[v]==0||dfs(c[v])) c[v]=u; return 1; return 0; void init() cnt=0; for(int i=1;i<=n;i++) head[i]=c[i]=0; for(int j=i;j<=n;j++) flag[i][j]=flag[j][i]=false; return; int main() //freopen("test.in","r",stdin); while(~scanf("%d%d",&n,&m)) init(); if(n==0&&m==0) break; if(m==0)printf("%d\n",n );continue; int A,B; while(m--) scanf("%d%d",&A,&B); flag[A][B]=true; add(A,B); floyd(); int ans=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) vis[j]=false; ans+=dfs(i); printf("%d\n",n-ans );
以上是关于POJ 2594 (传递闭包 + 最小路径覆盖)的主要内容,如果未能解决你的问题,请参考以下文章
POJ2594 Treasure Exploratio —— 最小路径覆盖 + 传递闭包
POJ 2594 Treasure Exploration(最小路径覆盖变形)
POJ 2594 Treasure Exploration(Floyd+最小路径覆盖)