1.

https://www.luogu.com.cn/problem/P1775

题目大意:

\(n\) 堆石子排成 一排 ,编号为 1, 2, 3,..., \(n\)。每堆石子有一定的质量,用一个整数来表述,现要将这 \(n\) 堆石子合并成为一堆,每次只能合并 相邻 的两堆,合并的代价为这两堆的质量之和,合并后这两堆石子相邻的石子将和新堆相邻,找出最合理的方式,使总代价最小,输出最小代价

思路:

定义 \(f[i][j] 为 i 到 j\) 的石子合并后最小的代价,这个结果是从两堆石子转移过来,我们定义中间节点为 \(k\),容易得到转移方程 \(f[i][j] = min(f[i][j],f[i][k] + f[k + 1][j] + 代价)\)代价 就是整个区间石子质量的和。
时间复杂度 \(O(n^3)\),数据范围为 200,所以可以过。
区间 \(dp\) 一般最外层循环都为长度。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 310;
int n, s[N], dp[N][N];
int main(){
	cin >> n;
	for (int i = 1; i <= n; i ++ ){
		cin >> s[i];
		s[i] += s[i - 1];
	}
	for (int len = 1; len < n; len ++ ){
		for (int i = 1; i <= n - len; i ++ ){
			int j = i + len;
			dp[i][j] = 1e9;
			for (int k = i; k < j; k ++ ){
				dp[i][j] = min(dp[i][k] + dp[k + 1][j] + s[j] - s[i - 1], dp[i][j]);
			}
		}
	}
	cout << dp[1][n] << "\n";
	return 0;
}

2.

https://www.luogu.com.cn/problem/P1880

题目大意:

\(n\) 个石子排成一个,求最小代价最大代价

思路:

拆成,按照区间 \(dp\) 操作即可。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 210;
int n, s[N], f[N][N], g[N][N], mx, mn = 1e9;
int main(){
	cin >> n;
	for (int i = 1; i <= n; i ++ ){
		cin >> s[i];
		s[i + n] = s[i];
	}
	for (int i = 1; i <= 2 * n; i ++ )
		s[i] += s[i - 1];
	for (int len = 1; len < n; len ++ ){
		for (int i = 1; i <= 2 * n - len; i ++ ){
			int j = i + len;
			f[i][j] = 1e9;
			g[i][j] = 0;
			for (int k = i; k < j; k ++ ){
				f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + s[j] - s[i - 1]);
				g[i][j] = max(g[i][j], g[i][k] + g[k + 1][j] + s[j] - s[i - 1]);
			}
		}
	}
	for (int i = 1; i <= n; i ++ ){
		mn = min(mn, f[i][i + n - 1]);
		mx = max(mx, g[i][i + n - 1]);
	}
	cout << mn << "\n" << mx << "\n";
	return 0;
}

3.

https://www.luogu.com.cn/problem/P5569

题目大意:

与 1 一样,数据范围改成 40000

思路:

http://t.zoukankan.com/winter-bamboo-p-11461352.html

代码:

posted on 2021-11-15 21:05  Hamine  阅读(68)  评论(0编辑  收藏  举报