【启发式搜索】Codechef March Cook-Off 2018. Maximum Tree Path

 有点像计蒜之道里的 京东的物流路径 

题目描述

给定一棵 N 个节点的树,每个节点有一个正整数权值。记节点 i 的权值为 Ai。
考虑节点 u 和 v 之间的一条简单路径,记 dist(u, v) 为其长度,gcd(u, v) 为路径上所有节点
(包含 u 和 v)的权值的最大公因子。min(u, v) 为路径上所有节点的权值的最小值。
请求出所有节点对 (u, v) 中 dist(u, v) · gcd(u, v) · min(u, v) 的最大值

输入格式

输入的第一行包含一个整数 T,代表测试数据的组数。接下来是 T 组数据。
每组数据的第一行包含一个整数 N,代表树中节点的个数。接下来一行包含 N 个整数
A1, A2, . . . , AN。
接下来 N − 1 行,每行包含三个整数 u, v, w,代表节点 u 和 v 之间连有一条长度为 w 的边。

输出格式

对于每组数据,输出一行,包含一个整数,代表所求答案

数据范围

• 1 ≤ T ≤ 100
• 2 ≤ N ≤ 10^5
• 2 ≤ ∑N ≤ 10^5
• 1 ≤ Ai ≤ 10^4
• 1 ≤ u, v ≤ N
• 1 ≤ w ≤ 10^5


题目分析

常规做法

和京东的物流路径不同的是,需要在外层枚举路径的gcd,并把两端点是gcd倍数的边存下,按照端点权值的较小值排序。之后就相当于是用这些边来和那题一样做了。

参见:[树的直径] Codechef March Cook-Off 2018. Maximum Tree Path

启发式搜索

我也不知道复杂度是多少

每一次搜索时若$dia*mn*gcd(dia为直径)<ans$就return。

 

 1 #include<bits/stdc++.h>
 2 typedef long long ll;
 3 const int maxn = 100035;
 4 
 5 struct Edge
 6 {
 7     int y,val;
 8     Edge(int a=0, int b=0):y(a),val(b) {}
 9 }edges[maxn<<1];
10 long long ans;
11 int tt,n,dia,S,T,a[maxn],dis[maxn];
12 int edgeTot,head[maxn],nxt[maxn<<1];
13 
14 int read()
15 {
16     char ch = getchar();
17     int num = 0;
18     bool fl = 0;
19     for (; !isdigit(ch); ch=getchar())
20         if (ch=='-') fl = 1;
21     for (; isdigit(ch); ch=getchar())
22         num = (num<<1)+(num<<3)+ch-48;
23     if (fl) num = -num;
24     return num;
25 }
26 int gcd(int a, int b){return !b?a:gcd(b, a%b);}
27 void addedge(int u, int v)
28 {
29     int c = read();
30     edges[++edgeTot] = Edge(v, c), nxt[edgeTot] = head[u], head[u] = edgeTot;
31     edges[++edgeTot] = Edge(u, c), nxt[edgeTot] = head[v], head[v] = edgeTot;
32 }
33 void dfs(int x, int fa, int c)
34 {
35     dis[x] = c;
36     for (int i=head[x]; i!=-1; i=nxt[i])
37         if (edges[i].y!=fa) dfs(edges[i].y, x, c+edges[i].val);
38 }
39 void fnd(int x, int fa, ll d, int g, int mn)
40 {
41     if (1ll*dia*g*mn <= ans) return;
42     if (ans < 1ll*d*g*mn) ans = 1ll*d*g*mn;
43     for (int i=head[x]; i!=-1; i=nxt[i])
44         if (edges[i].y!=fa)
45             fnd(edges[i].y, x, d+1ll*edges[i].val, gcd(g, a[edges[i].y]), std::min(mn, a[edges[i].y]));
46 }
47 void fndDiameter()
48 {
49     S = T = 0, dis[0] = -0x3f3f3f3f;
50     dfs(1, 1, 0);
51     for (int i=1; i<=n; i++)
52         if (dis[S] < dis[i]) S = i;
53     dfs(S, S, 0);
54     for (int i=1; i<=n; i++)
55         if (dis[T] < dis[i])
56             T = i, dia = dis[T];
57     fnd(S, S, 0, a[S], a[S]);
58 }
59 int main()
60 {
61     tt = read();
62     while (tt--)
63     {
64         n = read(), ans = dia = edgeTot = 0;
65         memset(head, -1, (n+2)<<2);
66         for (int i=1; i<=n; i++) a[i] = read();
67         for (int i=1; i<n; i++) addedge(read(), read());
68         fndDiameter();
69         for (int i=1; i<=n; i++)
70             fnd(i, i, 0, a[i], a[i]);
71         printf("%lld\n",ans);
72     }
73     return 0;
74 }

 

 

 

 

END

posted @ 2018-11-06 15:56  AntiQuality  阅读(304)  评论(0编辑  收藏  举报