SGU 149 解题手记
虽然题目描述的比较乱,但依稀看的出来,大意是给出一棵树,对每个节点求与它距离最远的点到它的距离。
对每个节点保存三个距离——向上扩展的最大距离(就是节点的深度)、向下扩展的最大距离(以及经过的第一个子节点)、向下扩展的次大距离(以及经过的第一个子节点),下面分别用dis[i,0],dis[i,1],dis[i,2]表示(经过的节点用point[i,1],point[i,2]表示),节点i,j之间的距离用g[i,j]表示。
dis[i,0]=dis[parent[i],0]+g[parent[i],i];
dis[i,1]=max{dis[j,1]+g[i,j] | while j is a child of i};
dis[i,2]=the_2nd_largest_of{dis[j,1]+g[i,j] | while j is a child of i};(这个不太好表述……)
最后的最大距离用maxdis[i]表示。
maxdis[i]=max{dis[i,0], dis[i,1], dis[parent[i],1]+g[parent[i],i]+g[parent[i],point[parent[i],1]] (if point[parent[i],1]<>i), dis[parent[i],2]+g[parent[i],i]+g[parent[i],point[parent[i],2]] (if point[parent[i],2]<>i)};
树用邻接表实现就可以了。
编了一组数据:
15
1 3
1 5
1 4
2 2
2 7
3 1
4 3
4 6
7 8
8 4
8 9
9 3
9 5
10 10
发现求maxdis的算法是错误的。
dis[i,0]改为表示经过父节点扩展出来的最大距离。
dis[i,0]=max{dis[parent[i],0]+g[parent[i],i], dis[parent[i],1]+g[parent[i],i] (if point[parent[i],1]<>i), dis[parent[i],2]+g[parent[i],i] (if point[parent[i],2]<>i)}
maxdis[i]=max{dis[i,0], dis[i,1]}
算法过程是,先求dis[i,1]和dis[i,2],然后求dis[i,0],最后求maxdis。
Submit 1: MLE on 13。把list改成vector。
Submit 2: AC。以后我再也不用list了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #include <cstdio> #include <list> #include <algorithm> #include <vector> using namespace std; struct treenode { int len; vector<int> child; }; treenode tree[10001]; int dis[10001][3]={{0}},point[10001][3]={{0}}; void get_dis12(int i,int p) { //dis[i][1]=0; point[i][1]=0; //dis[i][2]=0; point[i][2]=0; for (vector<int>::iterator j=tree[i].child.begin();j!=tree[i].child.end();++j) { get_dis12(*j,i); if (dis[*j][1]+tree[*j].len>dis[i][1]) { dis[i][2]=dis[i][1]; point[i][2]=point[i][1]; dis[i][1]=dis[*j][1]+tree[*j].len; point[i][1]=*j; } else if (dis[*j][1]+tree[*j].len>dis[i][2]) { dis[i][2]=dis[*j][1]+tree[*j].len; point[i][2]=*j; } } } void get_dis0(int i,int p) { dis[i][0]=max(dis[p][0]+tree[i].len,max((dis[p][1]+tree[i].len)*(point[p][1]!=i),(dis[p][2]+tree[i].len)*(point[p][2]!=i))); for (vector<int>::iterator j=tree[i].child.begin();j!=tree[i].child.end();++j) { get_dis0(*j,i); } } int main() { int n; scanf("%d",&n); for (int i=2;i<=n;++i) { int p; scanf("%d%d",&p,&tree[i].len); tree[p].child.push_back(i); } tree[1].len=tree[0].len=0; get_dis12(1,0); get_dis0(1,0); for (int i=1;i<=n;++i) { //printf("%d %d %d ",dis[i][0],dis[i][1],dis[i][2]); printf("%d\n",max(dis[i][0],dis[i][1])); } return 0; } |

5 Responses
可否发个地址。我搜到的都比较凌乱,且没题解
Reply
OIBH上可以搜到。pack-of-data-structures-and-algorithms 里面也有。
Reply
谢谢,但我找不到啊
Reply
请问网上哪有比较好的noi题解?(北极天南星的挂了)
Reply
从NOI2000开始,讲题大会就成了NOI的一项活动。在网上找到的NOI试题中一般都含有讲题大会的幻灯片。
Reply