比赛链接:
https://codeforces.com/contest/1675
F. Vlad and Unfinished Business
题目大意:
给定一棵 \(n\) 个节点的树,边权为 1,求出从点 \(x\) 出发,经过指定的 \(k\) 个点后,到达点 \(y\) 的最短路径长度。
思路:
如果不去其它点,那最短路径就是从 \(x\) 到 \(y\),通过一个数组记录下来,从父节点到子节点的路径为 1。
去往其它点的最短路径的起点一定是 \(x\) 到 \(y\) 的最短路径上的一个点,到了要去的点之后,回到起点,继续向目的地进发,也通过一个数组记录,从父节点到子节点的步数就为 2。
一遍 \(dfs\) 即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int T, k, n, x, y;
bool work[N], to[N];
vector <int> g[N];
void init(){
for (int i = 1; i <= n; i ++ ){
work[i] = false;
to[i] = false;
g[i].clear();
}
}
void dfs(int u, int fa){
for (auto v : g[u]){
if (v != fa){
dfs(v, u);
if (work[v])
work[u] = true;
if (to[v])
to[u] = true;
}
}
}
void solve(){
cin >> n >> k >> x >> y;
init();
for (int i = 1; i <= k; i ++ ){
int j;
cin >> j;
work[j] = true;
}
to[y] = true;
for (int i = 1; i < n; i ++ ){
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(x, 0);
int ans = 0;
for (int i = 1; i <= n; i ++ ){
if (i == x) continue;
if (to[i]) ans ++ ;
else if (work[i]) ans += 2;
}
cout << ans << "\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
cin >> T;
while (T -- )
solve();
return 0;
}
G. Sorting Pancakes
题目大意:
\(m\) 个饼,分成 \(n\) 堆排成一排,每一步操作可以将第 \(i(i > 1)\)堆的饼取出一个放到第 \(i - 1\) 堆中,或将第 \(j(j < n)\)堆的饼取出放到第 \(j + 1\) 堆中。问最少多少步可以让 \(n\) 堆饼的数量非递增。
思路:
定义 \(dp[i][j][k]\) 为第 \(i\) 堆饼为 \(k\) 个,前 \(i\) 堆饼的数量总和为 \(j\) 个时让前 \(i\) 堆饼的数量非递增的最小移动次数。
第 \(i\) 堆饼的数量要小于第 \(i - 1\) 堆饼的数量,所以枚举第 \(i - 1\) 堆饼的数量 \(x\)。
对于第 \(i\) 堆饼,因为前面 \(i - 1\) 堆已经排好了,那么它要将多余的饼移到后面去,或者将缺少的饼从后面移过来,所以先预处理一个前缀和,第 \(i\) 位的移动步数就是前缀和和 \(j\) 差值的绝对值。
可以得到转移方程 \(dp[i][j][k] = min(dp[i][j][k], dp[i - 1][j - k][x] + \lvert s[i] - j \rvert)\)。
参考:https://zhuanlan.zhihu.com/p/510066695
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 255;
int n, m, a[N], dp[N][N][N], ans = 1e9;
int main(){
cin >> n >> m;
memset(dp, 0x3f, sizeof dp);
for (int i = 1; i <= n; i ++ ){
cin >> a[i];
a[i] += a[i - 1];
}
dp[0][0][m] = 0;
for (int i = 1; i <= n; i ++ )
for (int j = 0; j <= m; j ++ )
for (int k = 0; k <= j; k ++ )
for (int x = k; x <= m; x ++ )
dp[i][j][k] = min(dp[i][j][k], dp[i - 1][j - k][x] + abs(a[i] - j));
for (int j = 0; j <= m; j ++ )
ans = min(ans, dp[n][m][j]);
cout << ans << "\n";
return 0;
}