1. 程式人生 > 其它 >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;
}