0%

2646. 最小化旅行的价格总和

2646.最小化旅行的价格总和

题目描述:

现有一棵无向、无根的树,树中有 n 个节点,按从 0n - 1 编号。给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示树中节点 aibi 之间存在一条边。

每个节点都关联一个价格。给你一个整数数组 price ,其中 price[i] 是第 i 个节点的价格。

给定路径的 价格总和 是该路径上所有节点的价格之和。

另给你一个二维整数数组 trips ,其中 trips[i] = [starti, endi] 表示您从节点 starti 开始第 i 次旅行,并通过任何你喜欢的路径前往节点 endi

在执行第一次旅行之前,你可以选择一些 非相邻节点 并将价格减半。

返回执行所有旅行的最小价格总和。

数据范围:

$1\le n \le 50, 1\le price[i] \le 1000, 1\le trips.len \le 100$

题解:

dfs加树形dp:

可以先对每个旅行进行 dfs,遍历出来经过的点,更新经过点的频率 freq[u]。最终的答案就是 $\sum freq[i] \times price[i]$ 。

下面需要考虑对哪些节点进行减半操作。假设 $dp[u][0/1]$ 分别表示对 $u$ 节点不减半和减半之后的最小价值。则 $u$ 不减半,那么 $v$ 可以减半,也可以不减半, $dp[u][0] = dp[u][0] + \min(dp[v][0], dp[v][1])$ ; $u$ 减半的话, $v$ 只能不减半,可以得到 $dp[u][1] = dp[u][1] + dp[v][0]$ 。注意每个节点的初始化,初始时 $dp[u][0] = freq[u] \times price[u], dp[u][1] = \frac{dp[u][0]}{2}$ .

LCA+树上差分+树形dp:

可以使用倍增法求出 $x, y$ 的 $LCA(x, y) = z$ 。使用差分计算频率,对 $x\rightarrow z, z \rightarrow y$ 路径上加 $1$ ,可以对 $cnt[z]+1, cnt[son[x]]-1, cnt[son[y]]-1$ 。

也可以对 $cnt[x]+1, cnt[y] + 1, cnt[z]-1, cnt[fa[z]]-1$ 。因为需要把 $z$ 也加一次,所以只能对 $z$ 加两次,减一次,然后对父亲减一次。下面这种使用的比较多。

因为下标是从 $0$ 开始的,可以先判断一下 $fa[lca][0]$ 是不是 $lca$ ,如果是的话,说明是根节点,就不用减父节点了。最后用一个 dfs 求出来所有点的权值和,从下往上求。

然后使用树形dp,求解最小价值。

代码:

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
class Solution
{
public:
const static int maxn = 1e5 + 10;
const static int maxm = 1e5 + 10;
const int INF = 0x3f3f3f3f;
vector<vector<int>> g;
vector<int> freq;
vector<vector<int>> dp;
bool find;
bool dfs(int u, int fa, int end)
{
freq[u]++;
if (u == end)
find = true;
if (find)
return true;
for (int i = 0; i < g[u].size(); ++i)
{
int v = g[u][i];
if (v == fa)
continue;
if (dfs(v, u, end))
return true;
}
freq[u]--;
return false;
}
void dfs2(int u, int fa, vector<int> &price)
{
dp[u][0] = freq[u] * price[u];
dp[u][1] = dp[u][0] >> 1;
for (int i = 0; i < g[u].size(); ++i)
{
int v = g[u][i];
if (v == fa)
continue;
dfs2(v, u, price);
dp[u][0] += min(dp[v][0], dp[v][1]);
dp[u][1] += dp[v][0];
}
}
int minimumTotalPrice(int n, vector<vector<int>> &edges, vector<int> &price, vector<vector<int>> &trips)
{
g.resize(n);
freq.resize(n);
dp.resize(n, vector<int>(2));
// dp[u][0] 不减半,dp[u][1] u减半
for (auto &edge : edges)
{
int u = edge[0], v = edge[1];
g[u].emplace_back(v);
g[v].emplace_back(u);
}
for (auto &trip : trips)
{
find = false;
dfs(trip[0], -1, trip[1]);
}
dfs2(0, -1, price);
return min(dp[0][0], dp[0][1]);
}
};
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
auto optimize_cpp_stdio = []()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
class Solution
{
public:
const static int maxn = 1e5 + 10;
const static int maxm = 1e5 + 10;
const int INF = 0x3f3f3f3f;
vector<vector<int>> g;
vector<vector<int>> fa;
vector<int> freq;
vector<vector<int>> dp;
vector<int> dep;
vector<int> log2;
void dfs(int u, int fa)
{
for (int i = 0; i < g[u].size(); ++i)
{
int v = g[u][i];
if (v == fa)
continue;
dep[v] = dep[u] + 1;
this->fa[v][0] = u;
dfs(v, u);
}
}
void dfs2(int u, int fa, vector<int> &price)
{
dp[u][0] = freq[u] * price[u];
dp[u][1] = dp[u][0] >> 1;
for (int i = 0; i < g[u].size(); ++i)
{
int v = g[u][i];
if (v == fa)
continue;
dfs2(v, u, price);
dp[u][0] += min(dp[v][0], dp[v][1]);
dp[u][1] += dp[v][0];
}
}
void dfs3(int u, int fa)
{
for (int i = 0; i < g[u].size(); ++i)
{
int v = g[u][i];
if (v == fa)
continue;
dfs3(v, u);
freq[u] += freq[v];
}
}
int query(int x, int y)
{
if (dep[x] < dep[y])
swap(x, y);
int tmp = dep[x] - dep[y];
while (dep[x] != dep[y])
{
x = fa[x][log2[tmp]];
tmp -= (1 << log2[tmp]);
}
if (x == y)
return x;
for (int i = log2[dep[x]]; i >= 0; --i)
{
if (fa[x][i] != fa[y][i])
{
x = fa[x][i];
y = fa[y][i];
}
}
return fa[x][0];
}
int minimumTotalPrice(int n, vector<vector<int>> &edges, vector<int> &price, vector<vector<int>> &trips)
{
g.resize(n);
freq.resize(n);
dep.resize(n);
dp.resize(n, vector<int>(2));
fa.resize(n, vector<int>(7));
log2.resize(n + 1);
// dp[u][0] 不减半,dp[u][1] u减半
for (int i = 2; i <= n; ++i)
log2[i] = log2[i >> 1] + 1;
for (auto &edge : edges)
{
int u = edge[0], v = edge[1];
g[u].emplace_back(v);
g[v].emplace_back(u);
}
dfs(0, -1);
for (int i = 1; i <= 6; ++i)
{
for (int u = 0; u < n; ++u)
{
fa[u][i] = fa[fa[u][i - 1]][i - 1];
}
}
for (auto &trip : trips)
{
int lca = query(trip[0], trip[1]);
freq[trip[0]]++;
freq[trip[1]]++;
freq[lca]--;
if (fa[lca][0] != lca)
freq[fa[lca][0]]--;
}
dfs3(0, -1);
dfs2(0, -1, price);
return min(dp[0][0], dp[0][1]);
}
};