1. 程式人生 > >PAT天梯賽練習題——L3-008. 喊山(鄰接表+BFS)

PAT天梯賽練習題——L3-008. 喊山(鄰接表+BFS)

L3-008. 喊山
時間限制
150 ms
記憶體限制
65536 kB
程式碼長度限制
8000 B
判題程式
Standard
作者
陳越
喊山,是人雙手圍在嘴邊成喇叭狀,對著遠方高山發出“喂—喂喂—喂喂喂……”的呼喚。呼喚聲通過空氣的傳遞,迴盪於深谷之間,傳送到人們耳中,發出約定俗成的“訊號”,達到聲訊傳遞交流的目的。原來它是彝族先民用來求援呼救的“訊號”,慢慢地人們在生活實踐中發現了它的實用價值,便把它作為一種交流工具世代傳襲使用。(圖文摘自:http://news.xrxxw.com/newsshow-8018.html

一個山頭呼喊的聲音可以被臨近的山頭同時聽到。題目假設每個山頭最多有兩個能聽到它的臨近山頭。給定任意一個發出原始訊號的山頭,本題請你找出這個訊號最遠能傳達到的地方。

輸入格式:

輸入第一行給出3個正整數n、m和k,其中n(<=10000)是總的山頭數(於是假設每個山頭從1到n編號)。接下來的m行,每行給出2個不超過n的正整數,數字間用空格分開,分別代表可以聽到彼此的兩個山頭的編號。這裡保證每一對山頭只被輸入一次,不會有重複的關係輸入。最後一行給出k(<=10)個不超過n的正整數,數字間用空格分開,代表需要查詢的山頭的編號。

輸出格式:

依次對於輸入中的每個被查詢的山頭,在一行中輸出其發出的呼喊能夠連鎖傳達到的最遠的那個山頭。注意:被輸出的首先必須是被查詢的個山頭能連鎖傳到的。若這樣的山頭不只一個,則輸出編號最小的那個。若此山頭的呼喊無法傳到任何其他山頭,則輸出0。

輸入樣例:
7 5 4
1 2
2 3
3 1
4 5
5 6
1 4 5 7
輸出樣例:
2
6
4
0

這題第一組資料可能不是很好理解,我一開始以為是3,但是後來發現1與3之間也有一條邊,因此1-2-3這條路徑預設作廢。即若A-B有多條路徑,那麼只算其中一條最短的。

然後就是BFS這裡面如何知道我當前BFS到第幾層呢,一開始我想比如1這個節點有2 3 4,然後2 3 4都往佇列裡壓,是當E[NOW].size()不等於0的時候意味這這個點可以繼續向外拓展,然後當前層數++,交上去中間兩組是錯的。除錯發現顯然是錯的,1-2、3、4,其實只有一層,但是實際上算了3層,因此原來的想法計算出來的是可拓展的次數而非層數。那如何去記錄當前的層數呢?用一個pair(結構體也可)來把兩個資料結合起來——當前點now和now所在層數d,每一次壓入佇列的時候把v的層數帶上,這樣就可以根據當前點來知道當前的層數。由於m題目沒說就不用前向星了省的段錯誤

程式碼:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f
#define MM(x) memset(x,0,sizeof(x))
#define MMINF(x) memset(x,INF,sizeof(x))
typedef long long LL;
const double PI=acos(-1.0);
const int N=10010;
typedef pair<int,int> pii;
vector<int>E[N];
int vis[N];
void init()
{
    for (int i=0; i<N; i++)
        E[i].clear();
}
int bfs(int s)
{
    MM(vis);
    queue<pii>Q;
    Q.push(pii(s,0));
    vis[s]=1;
    int d=0,p=s;
    while (!Q.empty())
    {
        pii now=Q.front();
        Q.pop();
        if(now.second>d)//層數大於d,更新資訊
        {
            p=now.first;
            d=now.second;
        }
        else if(now.second==d&&now.first<p)//層數相等但點更小,也更新
            p=now.first;
        int SZ=E[now.first].size();
        for (int i=0; i<SZ; i++)
        {
            int v=E[now.first][i];
            if(!vis[v])
            {
                Q.push(pii(v,now.second+1));
                vis[v]=1;//標記訪問過
            }   
        }
    }
    if(p==s)
        return 0;
    else
        return p;
}
int main(void)
{
    int m,n,k,i,j,a,b,c;
    while (~scanf("%d%d%d",&n,&m,&k))
    {
        init();
        for (i=0; i<m; i++)
        {
            scanf("%d%d",&a,&b);
            E[a].push_back(b);
            E[b].push_back(a);
        }
        for (i=0; i<k; i++)
        {
            scanf("%d",&c);
            printf("%d\n",bfs(c));
        }
    }
    return 0;
}