其他分享
首页 > 其他分享> > Codeforces Round #787 (Div. 3)

Codeforces Round #787 (Div. 3)

作者:互联网

比赛链接:

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;
}

标签:787,int,路径,堆饼,Codeforces,数量,Div,节点,dp
来源: https://www.cnblogs.com/Hamine/p/16242248.html