题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4283
题意:有队屌丝,每个人有一个愤怒值D,如果他是第K个上场,不开心指数就为(K-1)*D。但是边上有一个小黑屋(其实就是个堆栈)
可以先把人放置一下改变一下上场顺序,最后要得到总的不开心值最小。
数据比较小可以随意的套循环,简单的区间dp模版套3层for
设dp[i][j]表示从第i个人开始到第j个人愤怒总值是多少,可以想到
dp[i][j]=min(dp[i][j],dp[i+1][j]+a[i]*(k-i)(k表示i~j之间的数)+dp[k+1][j]+(k-i+1)*(sum[j]-sum[k])(sum表示前缀和))
这个转移方程很好理解,就是第i位的人要么先上要么放到后面。至于这个sum前缀和
为什么不会受到交换后影响,由于用到sum前缀和的都是移动后面的所以不会受到影响。
#include <iostream> #include <cstring> #include <string> #define inf 1<<27; using namespace std; int a[110] , dp[110][110] , sum[110]; int main() { int t , n , ans = 0; cin >> t; while(t--) { ans++; cin >> n; memset(sum , 0 , sizeof(sum)); memset(dp , 0 , sizeof(dp)); for(int i = 1 ; i <= n ; i++) { cin >> a[i]; sum[i] = sum[i - 1] + a[i]; dp[i][i] = 0; } for(int i = 1 ; i <= n ; i++) { for(int j = i + 1 ; j <= n ; j++) { dp[i][j] = inf; } } for(int i = 1 ; i <= n - 1 ; i++) { for(int j = 1 ; j <= n && i + j <= n ; j++) { for(int k = j ; k <= i + j ; k++) { dp[j][i + j] = min(dp[j][i + j] , dp[j + 1][k] + a[j] * (k - j) + dp[k + 1][j + i] + (k - j + 1) * (sum[i + j] - sum[k])); } } } cout << "Case #" << ans << ": " << dp[1][n] << endl; } return 0; }