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啦!小细节在代码里给注释。
——————————————
题目描述 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; }
相关文章推荐
- 【codevs 1036】商务旅行
- codevs 1036 商务旅行
- 【codevs 1036】商务旅行
- codevs 1036 商务旅行 LCA 解题报告
- codevs 1036 商务旅行 题解报告
- 【codevs 1036】商务旅行
- codevs1036 商务旅行 lcs倍增
- 倍增法-lca codevs 1036 商务旅行
- 【最近公共祖先】【块状树】CODEVS 1036 商务旅行
- Codves 1036 商务旅行
- codevs 1036 商务旅行 (LCA)
- CodeVs.1036 商务旅行 ( LCA 最近公共祖先 )
- 商务旅行_codevs1036_lca
- Codevs 1036 商务旅行
- Codevs 1036 商务旅行
- 倍增LCA code[vs]1036商务旅行
- 【WikiOI】【P1036】【商务旅行】【题解】【LCA】
- 1036 商务旅行
- CODE[VS] 1036商务旅行
- 1036 商务旅行