PTA 喊山 bfs

一个山头呼喊的声音可以被临近的山头同时听到。题目假设每个山头最多有两个能听到它的临近山头。给定任意一个发出原始信号的山头,本题请你找出这个信号最远能传达到的地方。

输入格式:

输入第一行给出3个正整数nmk,其中n\le10000)是总的山头数(于是假设每个山头从1到n编号)。接下来的m行,每行给出2个不超过n的正整数,数字间用空格分开,分别代表可以听到彼此的两个山头的编号。这里保证每一对山头只被输入一次,不会有重复的关系输入。最后一行给出k\le10)个不超过n的正整数,数字间用空格分开,代表需要查询的山头的编号。

输出格式:

依次对于输入中的每个被查询的山头,在一行中输出其发出的呼喊能够连锁传达到的最远的那个山头。注意:被输出的首先必须是被查询的个山头能连锁传到的。若这样的山头不只一个,则输出编号最小的那个。若此山头的呼喊无法传到任何其他山头,则输出0。

输入样例:

7 5 4
1 2
2 3
3 1
4 5
5 6
1 4 5 7

输出样例:

2
6
4

0

本来想用优先队列来着,想了半天还不如直接用老套路-_-!

#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <cmath> #include <algorithm> #include <vector> using namespace std; #define PI 3.1415926535897932 #define E 2.718281828459045 #define INF 0x3f3f3f3f #define mod 123456789 #define N 70 typedef long long ll; const int M=1005; int n,m; int cnt; int sx,sy,sz; int mp[M][12]; int pa[M],rankk[M]; int head[M*6],vis[M*10]; double dis[M][10]; ll prime[M*1000]; bool isprime[M*1000]; int lowcost[M],closet[M]; char st1[5050],st2[5050]; int len[M*6]; typedef pair<int ,int> ac; vector<int> g[M*10]; int dp[2005][2005]; bool has[10000]; int month[13]= {0,31,59,90,120,151,181,212,243,273,304,334,0}; int dir[8][2]= {{0,1},{0,-1},{-1,0},{1,0},{1,1},{1,-1},{-1,1},{-1,-1}}; bool isrun(int year) {     if((year%4==0&&year%100!=0)||(year%400==0))         return true;     return false; } void getpri() {     ll i;     int j;     cnt=0;     memset(isprime,false,sizeof(isprime));     for(i=2; i<1000000LL; i++)     {         if(!isprime[i])prime[cnt++]=i;         for(j=0; j<cnt&&prime[j]*i<1000000LL; j++)         {             isprime[i*prime[j]]=1;             if(i%prime[j]==0)break;         }     } } ll qk_mul(ll a,ll b,ll mo) {     ll t=0;     while(b)     {         if(b&1)             t=(t+a)%mo;         a=(a<<1)%mo;         b>>=1;     }     t%=mo;     return t; } ll qk_mod(ll a,ll b,ll mo) {     ll ans=1;     while(b)     {         if(b&1) ans=qk_mul(ans,a,mo);         a=qk_mul(a,a,mo);         b>>=1;     }     ans%=mo;     return ans; } int gcd(int a,int b) {     return b == 0 ? a : gcd(b, a%b); } int bfs(int x) {     int minx=x,mindis=0;//最小节点和最短距离     queue<ac> qu;     qu.push(ac(x,0));     vis[x]=1;     while(!qu.empty())     {         ac u=qu.front();         int z=u.first;         int y=u.second;         qu.pop();         if(mindis==y)         {             minx=min(z,minx);         }         if(mindis<y)         {             mindis=y;             minx=z;         }         for(int i=0;i<g[z].size();i++)         {             //minx=INF;             int v=g[z][i];             if(!vis[v])             {                 //minx=min(v,minx);                 vis[v]=1;                 qu.push(ac(v,y+1));             }         }     }     if(mindis==0)         return 0;     return minx; } int main() {     int i,j,t,k;     int u,v;     scanf("%d%d%d",&n,&m,&k);     for(i=1;i<=m;i++)     {         scanf("%d%d",&u,&v);         g[u].push_back(v);         g[v].push_back(u);     }     int ans;     for(i=0;i<k;i++)     {         memset(vis,0,sizeof(vis));         scanf("%d",&u);         ans= bfs(u);         printf("%d\n",ans);     }     return 0; }

### PTA 小费拼图 BFS算法 实现与解法 #### 问题分析 小费拼图通常涉及在一个二维网格中移动特定的元素以达到某种目标状态。此类问题可以通过广度优先搜索(BFS)求解,因为它能够找到从初始状态到目标状态的最短路径[^1]。 在该问题中,假设我们有一个大小为 `N×M` 的棋盘,某些位置可能有障碍物或其他特殊条件。我们需要通过一系列合法操作将初始状态转换为目标状态。每一步的操作可以定义为上下左右四个方向之一的移动。为了确保效率,我们可以利用队列来存储当前的状态以及到达该状态所需的步数[^2]。 以下是基于BFS的小费拼图解决方案的具体实现: --- #### 解决方案设计 ##### 数据结构的选择 - **队列 (Queue)**:用于保存待处理的状态及其对应的步数。 - **集合 (Set)** 或者布尔数组 (**Visited Array**):记录已经访问过的状态,防止重复计算。 ##### 状态表示 每个状态可以用字符串或者其他唯一标识符来描述整个棋盘的情况。例如,对于一个简单的 `3x3` 棋盘,可以直接将其展平成一维字符串 `"12345678."` 表示空白格的位置其他数字排列情况。 ##### 边界条件 需注意以下边界条件: - 如果起点就是终点,则无需任何移动即可完成任务。 - 若无法抵达目标状态(如存在不可逾越的障碍),则返回 `-1` 或其他标志值表明无解。 --- #### Python代码实现 下面提供了一个通用版本的Python程序框架,适用于大多数类似的滑动谜题问题: ```python from collections import deque def bfs_puzzle(start, target): # 定义可行动作:左移、右移、上移、下移 moves = [(0,-1),(0,1),(-1,0),(1,0)] n = int(len(start) ** 0.5) # 假设输入是一维化后的方阵 queue = deque([(start, 0)]) # 初始化队列为[(当前状态, 步数)] visited = set([start]) # 记录已访问过状态 while queue: current_state, steps = queue.popleft() if current_state == target: # 找到了目标状态 return steps index_of_empty = current_state.index(&#39;.&#39;) # 获取空位索引 row, col = divmod(index_of_empty, n) # 转换为空位坐标 for dr, dc in moves: # 遍历所有可行动作 new_r, new_c = row + dr, col + dc if not (0 <= new_r < n and 0 <= new_c < n): continue # 判断是否越界 swap_index = new_r * n + new_c # 新位置的一维索引 swapped_list = list(current_state) # 字符串转列表以便修改 swapped_list[index_of_empty], swapped_list[swap_index] = \ swapped_list[swap_index], swapped_list[index_of_empty] next_state = &#39;&#39;.join(swapped_list) if next_state not in visited: # 只扩展未访问的新状态 visited.add(next_state) queue.append((next_state, steps + 1)) return -1 # 如果穷尽所有可能性仍未找到解 # 测试用例 if __name__ == "__main__": start = "12345678." goal = ".87654321" result = bfs_puzzle(start, goal) print(f"Minimum number of moves required is {result}") ``` 此段代码实现了基本的功能需求并考虑了一些常见的优化措施,比如只允许有效的交换操作进入下一步探索阶段等[^3]。 --- #### 时间复杂度分析 由于每次仅改变单一字符形成新状态,并且只有当尚未见过这种配置才会加入等待序列之中;因此理论上讲,在理想情况下其时间消耗应接近线性增长关系相对于总节点数目而言。具体来说,如果把每一个独一无二的局面看做一个独立个体的话,那么整体运行耗时大致相当于 O(V+E),其中 V 是顶点数量而 E 则代表边的数量[^4]。 --- ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值