• 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.

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

  • 相关阅读:
    Linux I/O调度
    集群心跳机制
    如何修改集群的公网信息(包括 VIP) (文档 ID 1674442.1)
    AVL树(平衡二叉树)
    二叉搜索树
    二叉树及树的遍历
    python实现基数排序
    python之迷宫BFS
    python之迷宫DFS
    python实现队列
  • 原文地址:https://www.cnblogs.com/VisJiao/p/8485757.html
Copyright © 2020-2023  润新知