NYOJ 20 吝啬的国度 广度优先搜索

本文介绍了一种解决特定图论问题的方法,即在给定的城市网络中找到从起点到各城市的必经之路。通过使用广度优先搜索(BFS)和深度优先搜索(DFS)两种算法实现,并详细展示了如何将无根树转化为有根树来解决问题。

吝啬的国度

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 3
描述
在一个吝啬的国度里有N个城市,这N个城市间只有N-1条路把这个N个城市连接起来。现在,Tom在第S号城市,他有张该国地图,他想知道如果自己要去参观第T号城市,必须经过的前一个城市是几号城市(假设你不走重复的路)。
输入
第一行输入一个整数M表示测试数据共有M(1<=M<=5)组
每组测试数据的第一行输入一个正整数N(1<=N<=100000)和一个正整数S(1<=S<=100000),N表示城市的总个数,S表示参观者所在城市的编号
随后的N-1行,每行有两个正整数a,b(1<=a,b<=N),表示第a号城市和第b号城市之间有一条路连通。
输出
每组测试数据输N个正整数,其中,第i个数表示从S走到i号城市,必须要经过的上一个城市的编号。(其中i=S时,请输出-1)
样例输入
1
10 1
1 9
1 8
8 10
10 3
8 6
1 2
10 4
9 5
3 7
样例输出
-1 1 10 10 9 8 3 1 1 8

前两天刚学过图论中的最短路,今天做这道题,首先想到了用最短路的思想做。写了一个Bellman-Ford,超时了,原因是顶点数*边数太大。然后用广搜写了一下,AC。存储边时用了vector,记得每次都要清空vector。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include<stdio.h>  
  2. #include<string.h>  
  3. #include<vector>  
  4. #include<queue>  
  5. using namespace std;  
  6. const int N = 100010;  
  7. int pre[N], vis[N], n, s;  
  8. vector<int> vec[N];  
  9. void Init()  
  10. {  
  11.     for(int i = 1; i <= n; i++)  
  12.         pre[i] = i, vis[i] = 0;  
  13.     pre[s] = -1;  
  14. }  
  15. void bfs()  
  16. {  
  17.     queue<int> Q;  
  18.     Q.push(s);  
  19.     while(!Q.empty())  
  20.     {  
  21.         int t = Q.front();  
  22.         Q.pop();  
  23.         if(vis[t])  
  24.             continue;  
  25.         vis[t] = 1;  
  26.         for(int i = 0; i < vec[t].size(); i++)  
  27.         {  
  28.             int p = vec[t][i];  
  29.             if(!vis[p])  
  30.             {  
  31.                 pre[p] = t;  
  32.                 Q.push(p);  
  33.             }  
  34.         }  
  35.     }  
  36. }  
  37. int main()  
  38. {  
  39.     int t, i;  
  40.     scanf("%d",&t);  
  41.     while(t--)  
  42.     {  
  43.         memset(vec, 0, sizeof(vec));  
  44.         scanf("%d%d",&n,&s);  
  45.         int a, b;  
  46.         for(i = 0; i < n - 1; i++)  
  47.         {  
  48.             scanf("%d%d",&a,&b);  
  49.             vec[a].push_back(b);  
  50.             vec[b].push_back(a);  
  51.         }  
  52.         Init();  
  53.         bfs();  
  54.         printf("%d",pre[1]);  
  55.         for(i = 2; i <= n; i++)  
  56.             printf(" %d",pre[i]);  
  57.         printf("\n");  
  58.     }  
  59.     return 0;  
  60. }  

后来看讨论区,出题人说是把无根树转化为有根树,仔细一想,还真是。下面是代码:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /*无根树转有根树,s即为根*/  
  2. #include<stdio.h>  
  3. #include<string.h>  
  4. #include<vector>  
  5. using namespace std;  
  6. const int N = 100010;  
  7. int pre[N], n, s;  
  8. vector<int> vec[N];  
  9. void Init()  
  10. {  
  11.     for(int i = 1; i <= n; i++)  
  12.         pre[i] = i;  
  13.     pre[s] = -1;  
  14. }  
  15. void dfs(int u, int fa)  
  16. {  
  17.     int k = vec[u].size();  
  18.     for(int i = 0; i < k; i++)  
  19.     {  
  20.         int v = vec[u][i];  
  21.         if(v != fa)  
  22.         {  
  23.             pre[v] = u;  
  24.             dfs(v, u);  
  25.         }  
  26.     }  
  27. }  
  28. int main()  
  29. {  
  30.     int t, i;  
  31.     scanf("%d",&t);  
  32.     while(t--)  
  33.     {  
  34.         memset(vec, 0, sizeof(vec));  
  35.         scanf("%d%d",&n,&s);  
  36.         int a, b;  
  37.         for(i = 0; i < n - 1; i++)  
  38.         {  
  39.             scanf("%d%d",&a,&b);  
  40.             vec[a].push_back(b);  
  41.             vec[b].push_back(a);  
  42.         }  
  43.         Init();  
  44.         dfs(s,-1); //从根节点开始搜  
  45.         printf("%d",pre[1]);  
  46.         for(i = 2; i <= n; i++)  
  47.             printf(" %d",pre[i]);  
  48.         printf("\n");  
  49.     }  
  50.     return 0;  
  51. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值