zoukankan      html  css  js  c++  java
  • POJ2594

    原题链接

    Description

    给出一个有向无环图(|V|500,|E|5000),求最少用多少条路径才能覆盖所有点,路径可以相交。

    Solution

    首先考虑若路径不能相交如何实现:
    很明显n条路径一定可以覆盖,即每个顶点上都有一个自己到自己的路径。然后我们尝试合并这n条路径。

    把原来的有向图转换成一个二分图,每条边(u,v)转化为二分图中左边的u和右边的v的边。可以看到,二分图中的一个匹配就相当于合并了两条路径,覆盖所需的路径数就可以-1。所以答案就是n最大匹配数。
    然后对于路径可以相交的本题,可以先跑一遍Floyd算出u是否能到v,然后解法如上。正确性简单来说就是可以忽略原路径上的点只能用一次的限制,例如1-2-5和3-5-4的两条路径,现在3-5-4可以越过5而视为3-4。

    时间复杂度为O(n3)

    Code

    //Treasure Exploration
    #include <cstdio>
    #include <cstring>
    int const N=500+10;
    int n,m; bool ed[N][N];
    void Floyd()
    {
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    ed[i][j]|=ed[i][k]&ed[k][j];
    }
    int link[N]; bool used[N];
    int find(int u)
    {
        for(int v=1;v<=n;v++)
        {
            if(!ed[u][v]||used[v]) continue;
            used[v]=true;
            if(!link[v]||find(link[v])) {link[v]=u; return true;}
        }
        return false;
    }
    int match()
    {
        int res=0; memset(link,0,sizeof link);
        for(int i=1;i<=n;i++)
        {
            memset(used,0,sizeof used);
            if(find(i)) res++;
        }
        return res;
    }
    int main()
    {
        while(true)
        {
    
        scanf("%d%d",&n,&m); if(n==0&&m==0) break;
        memset(ed,0,sizeof ed);
        for(int i=1;i<=m;i++)
        {
            int u,v; scanf("%d%d",&u,&v);
            ed[u][v]=true;
        }
        Floyd();
        printf("%d
    ",n-match());
    
        }
        return 0;
    }

    P.S.

    多组测试数据,别忘了清数组啊。

  • 相关阅读:
    设计模式之工厂模式-抽象工厂(02)
    1036 跟奥巴马一起编程 (15 分)
    1034 有理数四则运算 (20 分)
    1033 旧键盘打字 (20 分)
    1031 查验身份证 (15 分)
    大学排名定向爬虫
    1030 完美数列 (25 分)二分
    1029 旧键盘 (20 分)
    1028 人口普查 (20 分)
    1026 程序运行时间 (15 分)四舍五入
  • 原文地址:https://www.cnblogs.com/VisJiao/p/8485757.html
Copyright © 2011-2022 走看看