您的位置:首页 > 其它

Codevs 1036:商务旅行——题解

2017-06-04 20:02 411 查看
这段故事仍然不属于勇者。

——————————————

题目描述 Description

某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。

假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。

你的任务是帮助该商人计算一下他的最短旅行时间。

输入描述 Input Description

输入文件中的第一行有一个整数N,1<=n<=30 000,为城镇的数目。下面N-1行,每行由两个整数a 和b (1<=a, b<=n; a<>b)组成,表示城镇a和城镇b有公路连接。在第N+1行为一个整数M,下面的M行,每行有该商人需要顺次经过的各城镇编号。

输出描述 Output Description

在输出文件中输出该商人旅行的最短时间。

样例输入 Sample Input

5

1 2

1 5

3 5

4 5

4

1

3

2

5

样例输出 Sample Output

7

————————————————

照理来说明白了倍增LCA之后就能AC的题。

然后路由器花了一整周的时间debug。

另外多亏了互联网的神奇功能。

看了大家的题解之后惊醒发现一个问题。

链式前向星一定要开二倍大!(很容易明白这个问题……然而debug……)

好的废话不多说,倍增LCA暴力解决就ok。

这题只要有思想就能AC啦!小细节在代码里给注释。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
int deep[30010]={0};//节点深度
int anc[30010][16]={0};
int m,n,cnt=0;
int cnt1=0,head[60020]={0}; //二倍大!
struct{
int to;
int next;
}edge[60020];//二倍大!
void add(int u,int v){//链前,u起点v终点
cnt1++;
edge[cnt1].to=v;
edge[cnt1].next=head[u];
head[u]=cnt1;
}
void dfs(int i){//搜索层数与每个节点的父亲使用
for(int j=head[i];j!=0;j=edge[j].next){
int k=edge[j].to;
if(anc[k][0]==0){
anc[k][0]=i;
deep[k]=deep[i]+1;
dfs(k);
}
}
return;
}
int suan(int i,int j){//求i与j的LCA
while(deep[i]!=deep[j]){//不同层化同层
int dd;
dd=abs(deep[i]-deep[j]);
int l,k;
for(l=15;;l--){
if(pow(2,l)<=dd){
break;
}
}
if(deep[i]>deep[j]){
i=anc[i][l];
}else{
j=anc[j][l];
}
}
if(i==j)return i;//这里要注意!!WA过一次
while(anc[i][0]!=anc[j][0]){//倍增找LCA
int k;
for(k=14;k>=0;k--){
if(anc[i][k]==anc[j][k])continue;
break;
}
i=anc[i][k];j=anc[j][k];
}
return anc[i][0];//LCA
}
int main(){
scanf("%d",&n);
anc[1][0]=0;deep[1]=deep[0]=1;//根节点指向0节点,0节点deep记为1
for(int i=1;i<=n-1;i++){
int a,b;
scanf("%d %d",&a,&b);//正反都要存
add(a,b);
add(b,a);
}
dfs(1);
for(int j=1;j<=14;j++){
for(int i=1;i<=n;i++){
anc[i][j]=anc[anc[i][j-1]][j-1];//2^n=2*2^(n-1)=2^(n-1)+2^(n-1)
}
}
scanf("%d",&m);
int start=1,end;
for(int i=1;i<=m;i++){
scanf("%d",&end);
cnt+=deep[start]+deep[end]-2*deep[suan(start,end)];
start=end;
}
printf("%d",cnt);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: