POJ 2594 (传递闭包 + 最小路径覆盖)

题目链接: 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
#include
#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 (传递闭包 + 最小路径覆盖))