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

来源:互联网 发布:腾讯软件管家官方下载 编辑:程序博客网 时间:2024/05/16 15:48

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

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

#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;}


0 0