[关闭]
@Gary-Ying 2018-01-29T05:53:05.000000Z 字数 2100 阅读 1198

最大Xor路径 | 解题报告

编程 解题报告


Description
求出这棵带边权的树的一条最大Xor路径
Input
第一行,一个整数N,表示一颗树有N个节点,接下来N-1行,每行三个整数a,b,c表示节点a和节点b之间有条权值为c的边(2<=n<=100000,1< a,b <=N,C<=2^31-1)
Output
输出仅一行,即所求的带边权树的Xor最大路径。

样例输入
4
1 2 3
1 3 4
1 4 7
样例输出
7

算法1 - 暴力的DFS

使用1遍DFS遍历可以扫描出n个节点到root(根节点)的XOR路径,时间复杂度为 O(n);那么我们可以通过n遍DFS扫描出所有节点到所有其他节点的XOR路径,从而求得最大值。综合下来,时间复杂度为O(n^2)。妥妥超时~~~

算法2 - 一个“无用”的优化

我们来观察一下算法1,对于这个O(n^2)的算法,我们肯定不能去优化DFS的一层,也就是说,我们只能在枚举n个节点的一层下手,能不能只进行1遍DFS呢?答案是肯定的。
假设有这样1棵树:

6
1 2 a
2 3 b
3 4 c
4 5 d
1 6 e

我们用d[i]记录i节点到1节点的XOR距离,那么
d[3]=a xor b
d[5]=a xor c xor d
而3->5的XOR距离为 b xor c xor d = d[3] xor d[5]
于是我们得到 对于任意两点i,j(i<>j),i到j的XOR距离为 d[i] xor d[j] (d[i]记录i节点到1节点的XOR距离)
那么原题就转化为 在d[1..n]中,找出一对i,j(i<>j),使d[i] xor d[j]最大。如果用暴力枚举的方法,时间复杂度仍然是 O(n^2)。

算法3 - 终极版优化

看上去我们已经不知道如何优化了,不如举几个例子。
98=(1100010)B
43=(101011)B
98 XOR 43 = (1001001)B = 73

算法2中,枚举i是必不可少的,所以我们只能在j上下功夫,要优化j,只能、必须做到精确查找对于D[i]最优的j。

代码(Pascal)

一遍AC!!!

  1. var
  2. head,d:array[0..100005] of longint;
  3. vet,val,next:array[0..200005] of longint;
  4. trie:array[0..3100005,0..2] of longint;
  5. edgenum,n,i,x,y,z,loc,ans,root,nodenum:longint;
  6. function max(a,b:longint):longint;
  7. begin
  8. if a>b then exit(a);
  9. exit(b);
  10. end;
  11. procedure addedge(u,v,cost:longint);
  12. begin
  13. inc(edgenum);
  14. vet[edgenum]:=v;
  15. val[edgenum]:=cost;
  16. next[edgenum]:=head[u];
  17. head[u]:=edgenum;
  18. end;
  19. procedure dfs(u,fa:longint);
  20. var
  21. e,v,cost:longint;
  22. begin
  23. e:=head[u];
  24. while e<>0 do
  25. begin
  26. v:=vet[e];
  27. cost:=val[e];
  28. if v<>fa then
  29. begin
  30. d[v]:=d[u] xor cost;
  31. dfs(v,u);
  32. end;
  33. e:=next[e];
  34. end;
  35. end;
  36. procedure ins(root,val,id:longint);
  37. var
  38. now,son,i:longint;
  39. begin
  40. now:=root;
  41. for i:=30 downto 0 do
  42. begin
  43. son:=val shr i and 1;
  44. if trie[now,son]=0 then
  45. begin
  46. inc(nodenum);
  47. trie[now,son]:=nodenum;
  48. end;
  49. now:=trie[now,son];
  50. end;
  51. trie[now,2]:=id;
  52. end;
  53. function find_trie(root,key:longint):longint;
  54. var now,son,i:longint;
  55. begin
  56. now:=root;
  57. for i:=30 downto 0 do
  58. begin
  59. son:=key shr i and 1;
  60. if trie[now,son xor 1]<>0 then now:=trie[now,son xor 1]
  61. else now:=trie[now,son];
  62. end;
  63. exit(trie[now,2]);
  64. end;
  65. begin
  66. readln(n);
  67. edgenum:=0;
  68. for i:=1 to n-1 do
  69. begin
  70. readln(x,y,z);
  71. addedge(x,y,z);
  72. addedge(y,x,z);
  73. end;
  74. dfs(1,-1);
  75. root:=1; nodenum:=1;
  76. for i:=1 to n do
  77. ins(root,d[i],i);
  78. ans:=d[1] xor d[2];
  79. for i:=1 to n do
  80. begin
  81. loc:=find_trie(root,d[i]);
  82. ans:=max(ans,d[i] xor d[loc]);
  83. end;
  84. writeln(ans);
  85. end.

算法链接

Trie树(字典树)

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注