You Are the One HDU - 4283 区间dp
题意:有一队人排队,每个人焦虑因数di,每个等前面(k-1)个人的焦虑度为di*(k-1),问给你重新排序,最小焦虑度为多少。
思路:区间dp
该状态转移方程还是令人焦灼的,假设把所有人分成俩区间,一个[i+1,k],一个[k+1,j](i+1≤k<j)
如果d[i]先进去,则后面的焦灼度增加量为dp[i+1][k]*(d[i]*(k-1))+dp[k+1][j]*((k + 1 - i) * (sum[j] - sum[k]));(其中sum代表的是从k到j总的焦灼度和)
于是就有了个状态转移方程:
dp[i][j] = min(dp[i][j], dp[i+1][k]+d[i]*(k-i) + dp[k + 1][j]+(k + 1 - i) * (sum[j] - sum[k]));
废话不多说,直接进入代码环节
#include<iostream> #include<algorithm> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define ll long long #define N 205 #define rep(i,l,r) for(i=l;i<=r;i++) const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; #define eps 0.00000001//偏差值1e8 #define pi acos(-1.0)//高精度圆周率 const int maxp = 1010; //点的数量 int a[N]; int dp[N][N]; int w[N]; int sum[N]; int main() { int i, j, k; int n, ret = 0, m, maxn = 0, count = 0; int t, x,y, len; cin >> t; while (t--) { count++; cin >> n; rep(i, 1, n) { cin >> a[i]; sum[i] = sum[i - 1] + a[i]; } rep(i, 0, n) rep(j, i + 1, n) dp[i][j] = INF; rep(len, 1, n) { rep(i, 1, n) { j = i + len - 1; if (j > n)break; rep(k, i, j) { dp[i][j] = min(dp[i][j], dp[i+1][k]+a[i]*(k-i) + dp[k + 1][j]+(k + 1 - i) * (sum[j] - sum[k])); } } } printf("Case #%d: %d\n", count, dp[1][n]); } }