石子合并 区间dp模板
题意:中文题
Description
在操场上沿一直线排列着 n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的两堆石子合并成新的一堆, 并将新的一堆石子数记为该次合并的得分。允许在第一次合并前对调一次相邻两堆石子的次序。
计算在上述条件下将n堆石子合并成一堆的最小得分。
Input
输入数据共有二行,其中,第1行是石子堆数n≤100;
第2行是顺序排列的各堆石子数(≤20),每两个数之间用空格分隔。
Output
输出合并的最小得分。
Sample Input
3
2 5 1
Sample Output
11
Source
NOI1995
题解:区间dp,交换的处理
代码
#include<iostream> #include<cstdlib> #include<algorithm> using namespace std; #define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++) #define per(i,j,k) for(int i = (int)j;i >= (int)k;i --) #define mmm(a,b) memset(a,b,sizeof(a)) #define pb push_back #define mp make_pair; const int maxn=1e2+5; int n; int a[maxn]; int dp[maxn][maxn]; int main() { cin >> n; //fill(dp, dp + maxn*maxn, 1e9); int ans = 1e9; rep(i, 1, n)cin >> a[i], dp[i][i] = 0; rep(i, 1, n-1) { swap(a[i], a[i + 1]); rep(len, 2, n)//len rep(i, 1, n - len + 1)//begin { dp[i][i + len - 1] = 1e9; int sum = 0; rep(j, i, i + len - 1)sum += a[j]; rep(k, i, len + i - 2)//k { dp[i][i + len - 1] = min(dp[i][i + len - 1], dp[i][k] + dp[k + 1][i + len - 1] + sum); } } ans=min(ans,dp[1][n]); swap(a[i], a[i + 1]); } cout << ans; cin >> n; }
成功的路并不拥挤,因为大部分人都在颓(笑)