题目链接
2 5 1 2 3 4 5 5 5 4 3 2 2
Case #1: 20 Case #2: 24
题意:n个人排队上台,每个人有个屌丝值Di,每个人的不高兴值为:(在他前面上台的人的个数)*(他的屌丝值)。现在有一个小黑屋:导演可以把让一个人进人小黑屋,让他之后的人比他先上台,最先进入小黑屋的人最后离开。(一个人只能进入一次小黑屋)。问所有人的不高兴值的总和最少为多少?
题解:如果我们考虑第一个上台的人是谁,问题不好解决。反过来,如果我们考虑最后一个上台的人是谁,这个问题就可以解决了。对于队列中的1到n个人,假设第i个人最后上台,显然区间[1,i-1]和区间[i+1,n]可以分别看成独立的问题解决。所以,我们可以用动态规划解决这个问题。
用dp[l][r] 表示区间[l,r] 的人上完台(小黑屋中没有剩下这个区间的人)的最小不高兴值。
转移的时候,我们考虑该区间最后一个上台的人为i,那么:
dp[l][r]=min(dp[l][r],Di*(r-l)+dp[l][i-1]+dp[i+1][r]+(D(i+1)+D(i+2)+.....Dr)*(i-l)));
代码如下:
#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<string> #include<stack> #include<math.h> #define nn 110 #define inff 0x3fffffff #define eps 1e-8 #define mod 1000000007 typedef long long LL; const LL inf64=LL(inff)*inff; using namespace std; int n; int a[nn]; int dp[nn][nn]; int sum[nn]; int cost(int l,int r,int x) { if(l>r) return 0; return (sum[r]-sum[l-1])*(l-x-1); } int dfs(int l,int r) { if(l>r) return 0; if(dp[l][r]!=-1) return dp[l][r]; if(l==r) return dp[l][r]=0; int i; dp[l][r]=inff; for(i=l;i<=r;i++) { dp[l][r]=min(dp[l][r],a[i]*(r-l)+dfs(l,i-1)+dfs(i+1,r)+cost(i+1,r,l)); } return dp[l][r]; } int main() { int t,i; scanf("%d",&t); int cas=1; while(t--) { scanf("%d",&n); sum[0]=0; for(i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } memset(dp,-1,sizeof(dp)); printf("Case #%d: ",cas++); printf("%d\n",dfs(1,n)); } return 0; }