📜  门| GATE-CS-2005 |第 66 题(1)

📅  最后修改于: 2023-12-03 14:58:26.537000             🧑  作者: Mango

门 | GATE-CS-2005 | 第 66 题

题目描述

有 n 个人和一间黑屋子。第一天,恶魔把每个人从黑屋子里随机地选出一个位置,然后他们都被锁在了这个位置上。第二天,任何两个人都可以通过进入堂而皇之的大门相互寻找,但如果他们距离太远,他们将无法相互看到(使用覆盖范围小于某个阈值)。如果某个人能够找到所有其他 n-1 个人,那么他获胜。以下是一个可行的策略,帮助你获胜:

  • 从黑屋子选择一个人作为起始点(他是唯一的已知点),然后使用广度优先搜索来在黑屋子里找到其他的人。
  • 取一个属于刚刚找到的人们的位置,再以此作为起点执行广度优化搜索算法,找到更多的人。
  • 多次执行这个过程直到找到所有的人。

你的工作是写一个程序,模拟一个成功的策略。(GATE-CS-2005)

算法说明

暴力搜索不是一个好的解决方案,时间复杂度为 O(n^2)。我们需要一个更快的算法,时间复杂度为 O(n log n) 或 O(n)。

以下是一个线性时间复杂度算法:

  1. 随机选择一个人作为起始点。
  2. 使用广度优先搜索来寻找其他 n-1 个人。
  3. 如果找到的人数为 n,输出结果并退出。
  4. 否则,找出与找到的人中最远距离最近的人,以此为起点执行广度优先搜索。
  5. 重复步骤 3 和 4 直到找到所有人。
代码片段

以下是该算法的 C++ 代码,其中 bfs 函数是广度优化搜索函数:

#include<bits/stdc++.h>
using namespace std;
const int INF=1<<20;
const int MAXN=1e3+7;

int G[MAXN][MAXN],n,d[MAXN],vis[MAXN];

int bfs(int s){
    queue<int> q;
    memset(d,INF,sizeof(d));
    memset(vis,0,sizeof(vis));
    d[s]=0;vis[s]=1;q.push(s);
    while(!q.empty()){
        int x=q.front();q.pop();vis[x]=0;
        for(int i=1;i<=n;i++){
            if(G[x][i] && d[i]>d[x]+1){
                d[i]=d[x]+1;
                if(!vis[i])vis[i]=1,q.push(i);
            }
        }
    }
    int mx=0;
    for(int i=1;i<=n;i++)
        if(d[i]>mx)mx=d[i];
    return mx;
}

int main(){
    srand(time(0));
    cin>>n>>d;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)
            G[i][j]=G[j][i]=0;
    }
    for(int i=1;i<=n;i++){
        int a,b;
        cin>>a>>b;
        G[a][b]=G[b][a]=1;
    }
    int p=rand()%n+1,res=0;
    while(1){
        res=bfs(p);
        if(res<=d){
            cout<<p<<endl;return 0;
        }
        int mx=-1,tmp;
        for(int i=1;i<=n;i++){
            if(d[i]>mx){
                mx=d[i];
                tmp=i;
            }
        }
        p=tmp;
    }
    return 0;
}
总结

本题中的算法的时间复杂度为 O(n),基本上接近于最优的解。由于此算法使用了广度优先搜索,因此它需要一个队列来帮助对搜索维持进一步的跟踪。如果我们只是暴力搜索,则时间复杂度将为 O(n^2),这显然是不可取的。