题意:n个人要入场选秀,给定他们的屌丝值D,可以用一个栈来调整顺序,第i个人第j个入场的不开心值为Di*(j-1),问所有人不开心值的总和最小是多少?(n<=100)
这明显是区间DP的套路题,对于一个区间[L,R],先将L推进栈里,枚举第L个人第k个进场,那么第一个入场的人可以推出为L+k-1,那么就分成了{L},[L+1,L+k-1],[L+k,R]三个子区间,其中L的不开心值为D[L]*(k-1),[L+1,L+k-1]的不开心值为dp[L+1][L+k-1],而对于[L+k,R]的不开心值,由于这些人要等k个人,所以不开心值要整体加上k*(S[R]-S[L+k-1]),最终的不开心值为k*(S[R]-S[L+k-1])+dp[L+k][R],可得状态转移方程如下:
dp[L][R]=min{D[L]*(k-1)+dp[L+1][L+k-1]+k*(S[R]-S[L+k-1])+dp[L+k][R]}
#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define FOR(i,x,y) for(int i=(x);i<=(y);i++) #define DOR(i,x,y) for(int i=(x);i>=(y);i--) using namespace std; int A[103],S[103]; int dp[103][103]; int main() { int kase,n; scanf("%d",&kase); FOR(k,1,kase) { scanf("%d",&n); S[0]=0; FOR(i,1,n) { scanf("%d",&A[i]); S[i]=S[i-1]+A[i]; } FOR(l,1,n) //区间长度为l FOR(L,1,n-l+1) { int R=L+l-1; dp[L][R]=1e9; FOR(k,1,l) //枚举L是第几个入场的 dp[L][R]=min(dp[L][R],A[L]*(k-1)+dp[L+1][L+k-1]+dp[L+k][R]+k*(S[R]-S[L+k-1])); } printf("Case #%d: %d\n",k,dp[1][n]); } return 0; }