【LCA 倍增法】【codevs 1036 商务旅行】
2016-04-25 17:44
363 查看
题目
题目描述 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
在输出文件中输出该商人旅行的最短时间。
贴另一优美的代码。2333.
题目描述 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
在输出文件中输出该商人旅行的最短时间。
#include<cstdio> #include<cmath> #include<iostream> using namespace std; #define maxn 30010 #define exc(a,b) { a = a^b;b = a^b;a = a^b; } #define cint const int& int p[maxn][16]; struct edge{ int to; edge* next; }; edge* head[maxn]; int dep[maxn]; void dfs(cint u,cint fa){ dep[u] = dep[fa]+1; p[u][0] = fa; for(int i = 1;i <= 15;++i) p[u][i] = p[p[u][i-1]][i-1]; for(edge* i = head[u];i!=NULL;i=i->next){ if(i->to != fa) dfs(i->to,u); } } void adde(cint a,cint b){ edge* n = new edge; n->to = b;n->next = head[a]; head[a] = n; } int lca(int a,int b){ if(dep[a]>dep[b]) exc(a,b); for(int i = 15;i>=0;--i)if(dep[a]<=dep[b] - (1<<i)) b = p[b][i]; if(a==b) return a; for(int i = 15;i >= 0;--i){ if(p[a][i]==p[b][i]) continue; a = p[a][i];b = p[b][i]; } return p[a][0]; } int main(){ int n,m; scanf("%d",&n); int a,b; for(int i = 1;i < n;++i){ scanf("%d%d",&a,&b); adde(a,b);adde(b,a); } dfs(1,0); int ans(0); scanf("%d",&m); scanf("%d",&a); for(int i = 1;i < m;++i){ scanf("%d",&b); ans += dep[a] + dep[b] - 2 * dep[lca(a,b)]; a = b; } cout << ans; return 0; }
贴另一优美的代码。2333.
#include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> #define maxn 30100 using namespace std; int n; struct edge{ int to,next; }e[4*maxn]; int k=1,head[maxn]; int p[maxn][25]; int d[maxn]; void adde(int a,int b) { e[k].to=b; e[k].next=head[a]; head[a]=k++; } //首先预处理出所有的p[i][j],并计算每个点的深度d[i] void dfs(int u,int fa)///从根结点u开始dfs,u的父亲是fa { d[u]=d[fa]+1;//u的深度为它父亲的深度+1 p[u][0]=fa;//u向上走2^0步到达的结点是其父亲 for(int i=1;i<=20;i++)p[u][i]=p[p[u][i-1]][i-1];//预处理p时,保证能从u走到p[u][i] for(int i=head[u];i!=-1;i=e[i].next)///对于u的每个儿子 { int v=e[i].to; if(v!=fa)dfs(v,u);///递归处理以v为根结点的子树 } } int m; int ans=0; int lca(int a,int b) { if(d[a]>d[b])swap(a,b);///保证a点在b点上面 for(int j=20;j>=0;--j) if(d[a] <= d[b] - (1<<j))b = p[b][j]; ////将b点向上移动到和a的同一深度 if(a==b)return a;//如果a和b相遇 for(int i=20;i>=0;--i)//a,b同时向上移动 { if(p[a][i]==p[b][i]) continue;//如果a,b的2^j祖先相同,则不移动 a = p[a][i];b = p[b][i];//否则同时移动到2^j处 } return p[a][0];//返回最后a的父亲结点 } /******Program Begin*********/ int main() { memset(head,-1,sizeof(head)); scanf("%d",&n); for(int i=1;i<=n;i++)d[i]=1; int a,b; for(int i=1;i<n;i++) { scanf("%d%d",&a,&b); adde(a,b); adde(b,a); } dfs(1,0); scanf("%d",&m); scanf("%d",&a); ans=0; for(int i=1;i<m;i++) { scanf("%d",&b); ans+=d[a]+d[b]-2*d[lca(a,b)]; a=b; } printf("%d",ans); return 0; } /*******Program End**********/
相关文章推荐
- JavaScript基础学习(二)—JavaScript基本概念
- 新建mysql服务
- 多进程并发编程----基于高级的预先创建进程池(accept使用文件上锁)的模型
- Tricks(四十三)—— 逆序的方式访问一个 list
- 区分copy构造、copy赋值
- 【图-树结构】树的重量
- 微信二维码支付
- 用组函数合计数据
- 【C#设计模式-建造者模式】
- requests库的简单函数
- js json
- invert
- 强大的原型链
- invert
- Hduoj5025 【广搜+状态压缩】
- Maven基础原理、项目搭建(纯手工无IDE)、最基本语法
- YT 督促训练 fzoj 2012Solve equation 各种进制转换为10进制
- linux shell 脚本基础编写
- 【剑指offer-Java版】10二进制中1的个数
- HashMap中红黑树操作实现