zoukankan      html  css  js  c++  java
  • poj 2594 Treasure Exploration(最小路径覆盖,可重点)

      题意:选出最小路径覆盖图中所有点,路径可以交叉,也就是允许路径有重复的点。

      分析:这个题的难点在于如何解决有重复点的问题~方法就是使用Floyd求闭包,就是把间接相连的点直接连上边,然后就是求最小路径覆盖了。我来大概解释一下为什么是对的,首先我们要明确,当我们重复利用一个点的时候,一定是有两个比较良好的路径相交了,而二分图是不允许这样的情况存在的,因为那必然存在了一个点有一个以上的出度或者入度了,而怎么避免这个问题呢,看下面的图:

      这就是针对这个问题的一个典型的模型,如果使用正常二分图,求得的匹配值为2,路径数为3(例如:2-3-5,1,4),但是如果我们把3用两次,那么求得的答案就是2了(例如:2-3-5,1-3-4).

    so,我们的解决办法就出来了,当(2-3-5)这个路径被选择的时候,我们在(1-3-4)这个路径时只要把3无视掉,直接在1-4之间建一条边就可以了,那样1-4就匹配成功了。这样所有含有交叉点的路径,都可以先选择一个路径,然后直接跨过交叉点连接一个,它所代表的仍然是经过交叉点的路径。

      有人也许会问,Floyd会压缩所有的边,会不会导致错误呢? 不会,比如这个图(1-4)和(1-5)都有边,在匹配中二分图是最大匹配,他会优先获得较多的匹配,最后无法找到增广路,才会考虑我们连接的边,不要因为边都被压缩了有一种答案会变小的错误。代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define maxn 510
    int maps[maxn][maxn],vis[maxn],link[maxn];
    int n,m;
    void floyd()
    {
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                if(!maps[i][j])
                {
                    for(int k = 1; k <= n; k++)
                    {
                        if(maps[i][k] && maps[k][j])
                        {
                            maps[i][j] = 1;
                            break;
                        }
                    }
                }
            }
        }
    }
    bool dfs(int u)
    {
        for(int i = 1; i <= n; i++)
        {
            if(maps[u][i] && !vis[i])
            {
                vis[i] = 1;
                if(link[i] == -1 || dfs(link[i]))
                {
                    link[i] = u;
                    return true;
                }
            }
        }
        return false;
    }
    int slove()
    {
        int ans = 0;
        memset(link,-1,sizeof(link));
        for(int i = 1; i <= n; i++)
        {
            memset(vis,0,sizeof(vis));
            if(dfs(i)) ans++;
        }
        return ans;
    }
    int main()
    {
        int x,y;
        while(~scanf("%d%d",&n,&m))
        {
            if(!n && !m) break;
            memset(maps,0,sizeof(maps));
            while(m--)
            {
                scanf("%d%d",&x,&y);
                maps[x][y] = 1;
            }
            floyd();
            printf("%d
    ",n-slove());
        }
        return 0;
    }
  • 相关阅读:
    net5 webapi中 SwaggerUI如何进行版本控制
    动态菜单/权限管理的实现效果(数据前提:须做好 菜单、按钮、角色、用户等相关功能)
    MOS管的引脚,G、S、D分别代表什么?
    关系再好,也不要跟人透露这三个隐私。
    Linux 学习笔记
    算法 蓄水问题
    算法 等概率问题
    算法 字符串类问题(一)
    效率,生产力和用户友好的应用程序是GeneXus为Salinas集团带来的一些好处
    Multillantas Nieto通过智能设备和GeneXus将生产率提高了50%
  • 原文地址:https://www.cnblogs.com/jifahu/p/5524618.html
Copyright © 2011-2022 走看看