poj 2594 Treasure Exploration(可重点最小路径覆盖)(二分匹配+Floyd求传递闭包)

题意:不是赤裸裸的最小路径覆盖(走遍所有的点),正常的最小路径覆盖中两个人走的路径不能有重复的点,而本题可以重复。

分析:我们仍可将问题转化为最小路径覆盖。如果一个人需要经过另一个人走过的点的时候,让他直接从该点上空飞过去,越过该点,直接走下一个点。如果我们赋予每个人这种能力,那么求得的无重复点的最小路径覆盖结果,就是题目要求的结果,因为需要重复的地方只要飞过去,就可以不重复了。赋予这个能力的方法就是把所有点能间接到达的点全都改为直接到达。然后正常求最小路径覆盖即可。

#include <iostream>
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX=510;
int map[MAX][MAX];  //图
int vis[MAX];    //访问标志
int match[MAX];  //匹配数组
int N,M;    //N:顶点数   M:边数
bool Dfs(int u)  //判断顶点u是否可以找到可匹配的顶点
{
     for (int v=1;v<=N;v++)
     {
          if (!vis[v] && map[u][v])
          {
               vis[v]=1;
               if (match[v]==0 || Dfs(match[v]))
               {
                    match[v]=u;
                    return true;
               }
          }
     }
     return false;
}
void Floyd()   //传递闭包:建新图
{
     for (int k=1;k<=N;k++)
     {
          for (int i=1;i<=N;i++)
          {
               for (int j=1;j<=N;j++)
               {
                    if (map[i][k] && map[k][j])  //顶点i和顶点j可到达
                    {
                         map[i][j]=1;
                    }
                }
           }
      }
}
int main()
{
      int i;
      int x,y;
      while (scanf("%d%d",&N,&M) && (N | M))
      {
            memset(map,0,sizeof(map));
            memset(match,0,sizeof(match));
            //输入边
            for (i=1;i<=M;i++)
            {
                  scanf("%d%d",&x,&y);  
                  map[x][y]=1;
            }
            //建新图
            Floyd();
            //求最大匹配
            int sum=0;
            for (i=1;i<=N;i++)
            {
                  memset(vis,0,sizeof(vis));
                  if (Dfs(i))
                  {
                        sum++;
                  }
            }
            printf("%d\n",N-sum);  //输出最小路径覆盖
      }
      return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值