zoukankan      html  css  js  c++  java
  • 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<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];
    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 );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-ans );
        }
    }
  • 相关阅读:
    简练软考知识点整理-项目采购管理简介
    简练软考知识点整理-项目风险管理简介
    SQL(replace)替换字段中指定的字符
    sh 脚本名字和./脚本名字有什么区别
    linux下tar命令解压到指定的目录
    查看文件MD5值
    Topo check failed. Mapred tasks exceed 1000000000
    cron表达式详解
    Linux下#!/usr/bin/env bash和#!/usr/bin/bash、#!/bin/bash的比较
    linux中seq命令用法
  • 原文地址:https://www.cnblogs.com/Absofuckinglutely/p/11393631.html
Copyright © 2011-2022 走看看