標籤:
《商務旅行》解題報告
by mps
【題目描述】
某首都城市的商人要經常到各城鎮去做生意,他們按自己的路線去做,目的是為了更好的節約時間。
假設有N個城鎮,首都編號為1,商人從首都出發,其他各城鎮之間都有道路串連,任意兩個城鎮之間如果有直連道路,在他們之間行駛需要花費單位時間。該國公路網路發達,從首都出發能到達任意一個城鎮,並且公路網路不會存在環。
你的任務是協助該商人計算一下他的最短旅行時間。
【輸入描述】
輸入檔案中的第一行有一個整數n,1<=n<=30 000,為城鎮的數目。下面N-1行,每行由兩個整數a 和b (1<=a, b<=n; a<>b)組成,表示城鎮a和城鎮b有公路串連。在第N+1行為一個整數M,下面的M行,每行有該商人需要順次經過的各城鎮編號。
【輸出描述】
在輸出檔案中輸出商人旅行的最短時間
【輸入範例】
5
1 2
1 5
3 5
4 5
4
1
3
2
5
【輸出範例】
7
【分析】
數學建模:建成一棵樹,求這些點逐個的樹上最短路徑,演算法LCA
兩個點的最短路徑=D(x)+D(y)-2*D(LCA(x,y))
D是根到點的最短路徑
很明顯,就是該點的深度
通過倍增即可求出,然後直接類比一下就OK了
【代碼】
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 const int MaxN=70001; 8 9 int deep[MaxN],p[MaxN][30];10 int n,q;11 12 struct list{13 int to,next;14 }e[MaxN];15 int head[MaxN],cnt=0;16 17 void addedge(int u,int v){18 cnt++;19 e[cnt].to=v;20 e[cnt].next=head[u];21 head[u]=cnt;22 }23 24 void init(){25 freopen("trip.in","r",stdin);26 freopen("trip.out","w",stdout);27 scanf("%d",&n);28 int i,u,v;29 for(i=1;i<n;i++){30 scanf("%d %d",&u,&v);31 addedge(u,v);32 addedge(v,u);33 }34 }35 36 int lca(int u,int v){37 if(deep[u]<deep[v])swap(u,v);38 int c=deep[u]-deep[v],i;39 for(i=0;i<=23;i++)40 if((1<<i)&c)41 u=p[u][i];42 for(i=23;i>=0;i--)43 if(p[u][i]!=p[v][i]){44 u=p[u][i];45 v=p[v][i];46 }47 if(u==v)return u;48 else return p[u][0]; 49 }50 51 void dfs(int u){52 int i;53 for(i=1;i<=23;i++){54 if(deep[u]<(1<<i))break;55 p[u][i]=p[p[u][i-1]][i-1];56 }57 for(i=head[u];i;i=e[i].next)58 if(!deep[e[i].to]){59 deep[e[i].to]=deep[u]+1;60 p[e[i].to][0]=u;61 dfs(e[i].to);62 }63 }64 65 void solve(){66 scanf("%d",&q);67 int i,u,v,ans=0,LCA;68 for(i=1;i<=n;i++)69 if(!deep[i]){70 p[i][0]=i;71 deep[i]=1;72 dfs(i);73 }74 scanf("%d",&u);75 for(i=2;i<=q;i++){76 scanf("%d",&v);77 LCA=lca(u,v);78 ans+=deep[u]+deep[v]-2*deep[LCA];79 u=v;80 }81 printf("%d",ans);82 }83 84 int main(){85 init();86 solve();87 return 0;88 }
《商務旅行》解題報告