標籤:memset div its 網路 n+1 output std des 檔案中
傳送門
Description
某首都城市的商人要經常到各城鎮去做生意,他們按自己的路線去做,目的是為了更好的節約時間。
假設有N個城鎮,首都編號為1,商人從首都出發,其他各城鎮之間都有道路串連,任意兩個城鎮之間如果有直連道路,在他們之間行駛需要花費單位時間。該國公路網路發達,從首都出發能到達任意一個城鎮,並且公路網路不會存在環。
你的任務是協助該商人計算一下他的最短旅行時間。
Input
輸入檔案中的第一行有一個整數N,1<=n<=30 000,為城鎮的數目。下面N-1行,每行由兩個整數a 和b (1<=a, b<=n; a<>b)組成,表示城鎮a和城鎮b有公路串連。在第N+1行為一個整數M,下面的M行,每行有該商人需要順次經過的各城鎮編號。
Output
在輸出檔案中輸出該商人旅行的最短時間。
Sample Input
5
1 2
1 5
3 5
4 5
4
1
3
2
5
Sample Output
7
思路
很裸的最近公用祖先的題目,跑一遍spfa記錄首都到各個城市的距離,然後找到兩點的最近公用祖先,這樣就可以根據距離以及最近公用祖先算出兩點的最短路了。
#include<bits/stdc++.h>using namespace std;const int maxn = 30005;int tot = 0,road[maxn],dis[maxn],flag[maxn],vis[maxn],head[maxn],fa[maxn],ancestor[maxn];struct Edge{int to,next;}edge[maxn<<1];int tt = 0,h[maxn],answer[maxn];struct Query{int q,next;int index;}qry[maxn<<1];void init(int N){for (int i = 0;i <= N;i++){fa[i] = i;ancestor[i] = 0;vis[i] = false;head[i] = h[i] = -1;}}void addedge(int u,int v){edge[tot] = (Edge){v,head[u]};head[u] = tot++;}void add_query(int u,int v,int index){qry[tt] = (Query){v,h[u],index};h[u] = tt++;qry[tt] = (Query){u,h[v],index};h[v] = tt++;}void spfa(){queue<int>que;memset(dis,0x3f,sizeof(dis));memset(flag,false,sizeof(flag));que.push(1);dis[1] = 0;flag[1] = true;while (!que.empty()){int u = que.front();que.pop();flag[u] = false;for (int i = head[u];i != -1;i = edge[i].next){int v = edge[i].to;if (dis[u] + 1 < dis[v]){dis[v] = dis[u] + 1;if (!flag[v]){que.push(v);flag[v] = true;}}}}}int find(int x){int r = x;while (r != fa[r])r = fa[r];int i = x,j;while (i != r){j = fa[i];fa[i] = r;i = j;}return r;}void Union(int x,int y){x = find(x),y = find(y);if (x == y)return;fa[y] = x;}void targin_LCA(int u){ancestor[u] = u;vis[u] = true;for (int i = head[u]; i != -1;i = edge[i].next){int v = edge[i].to;if (vis[v])continue;targin_LCA(v);Union(u,v);ancestor[find(u)] = u;}for (int i = h[u];i != -1;i = qry[i].next){int v = qry[i].q;if (vis[v]){answer[qry[i].index] = ancestor[find(v)];}}}int main(){int N,M,u,v,sum = 0;scanf("%d",&N);init(N);for (int i = 1;i < N;i++){scanf("%d%d",&u,&v); addedge(u,v);addedge(v,u);}spfa();scanf("%d",&M);scanf("%d",&road[0]);for (int i = 1;i < M;i++)scanf("%d",&road[i]),add_query(road[i-1],road[i],i);targin_LCA(1);for (int i = 1;i < M;i++){sum += dis[road[i]] + dis[road[i-1]] - 2*dis[answer[i]];}printf("%d\n",sum);return 0;}
codevs 1036 商務旅行(Targin求LCA)