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.

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

  • 相关阅读:
    NHibernate初学二之简单执行SQL及HQL、Linq
    Socket通信常用方法
    Android中自定义属性的使用
    四种常见的 POST 提交数据方式
    关于 Content-Type:application/x-www-form-urlencoded 和 Content-Type:multipart/related
    1、memcache的守护进程启动方式(2017-8-10)
    c++封装简单日志操作
    关于vector的内存释放
    Linux进程通信-共享内存
    Linux进程通信总结
  • 原文地址:https://www.cnblogs.com/VisJiao/p/8485757.html
Copyright © 2011-2022 走看看