HDU4283 You Are the One(区间DP)

HDU4283 You Are the One(区间DP)

Description
The TV shows such as You Are the One has been very popular. In order to meet the need of boys who are still single, TJUT hold the show itself. The show is hold in the Small hall, so it attract a lot of boys and girls. Now there are n boys enrolling in. At the beginning, the n boys stand in a row and go to the stage one by one. However, the director suddenly knows that very boy has a value of diaosi D, if the boy is k-th one go to the stage, the unhappiness of him will be (k-1)*D, because he has to wait for (k-1) people. Luckily, there is a dark room in the Small hall, so the director can put the boy into the dark room temporarily and let the boys behind his go to stage before him. For the dark room is very narrow, the boy who first get into dark room has to leave last. The director wants to change the order of boys by the dark room, so the summary of unhappiness will be least. Can you help him?
Input
 The first line contains a single integer T, the number of test cases. For each case, the first line is n (0 < n <= 100)
 The next n line are n integer D1-Dn means the value of diaosi of boys (0 <= Di <= 100)
Output
 For each test case, output the least summary of unhappiness .

题意

每个人都有一个屌丝值D,如果这个人第k个上场,他的不开心指数就是(k-1)D。题目问这些屌丝应该如何上场,也就是入栈来改变自己的上场顺序,才能使得最终不开心指数的总和最小,并输出不开心指数。dp[i][j]表示区间[i,j]的不开心指数最小值。状态转移方程为dp[i][j]=min(dp[i][j],dp[i+1][i+k-1]+(k-1)x[i]+dp[i+k][j]+k(sum[j]-sum[i+k-1]))。x[i]是每个人的屌丝值,sum[i]是屌丝值的前缀和。k表示i是在第k个上场的,则区间[i+1,i+k-1]的人也就是总数为k-1的人一定是在i之前上场的,则从区间[i+k,j]的人一定是在i之后上场的。这就转化出了3个子问题。dp[i+1][i+k-1],x[i],dp[i+k][j]。第一个区间[i+1,i+k-1]的人因为其是在i之前上场的,所以我们直接加上dp[i+1][i+k-1]就好了。而i是在第k个上场的,所以我们要加上x[i](k-1)。第二个区间[i+k,j]的人是在i之后上场的,我们如果把这个作为一个单独的子问题处理的话,这个区间的第一个人是在这个子问题中是第一个人上场的,但是我们要把这个区间转移到dp[i][j]中去,所以第一个人实际上是第k+1个上场的,第二个人实际上是第k+2个上场的,根据题目意思,每个人的不开心指数是一个累加的过程,多等一个人,其不开心指数就累加一个x[i],因此这些人已经等了k个人了,所以最终这个区间的dp值要加上k*(sum[j]-sum[i+k-1]))。我们也可以把i后面等待的人看成一个整体。
假设有1,2,3,4,5,想让1在第三个上场,则顺序就是,1,2,3依次入栈,然后3,2,1出栈,则队列顺序就变成了3,2,1,4,5

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<stack>
#include<vector>
#include<functional> 
#include<map>
using namespace std;
typedef long long ll;
const int N=1e5+10,NN=2e3+10,INF=0x3f3f3f3f;
const ll MOD=1e9+7;
int n,T=0;
int sum[N],x[N];
int dp[NN][NN],s[NN][NN];
void minval(){
	for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) dp[i][j]=INF;//因为求的是最小的不开心指数和,所以这里把所有的[i,j]区间设为INF
	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+x[i];//计算前缀和
	for(int len=1;len<=n-1;len++){//枚举区间大小
		for(int i=1;i<=n-len;i++){//枚举i
			int j=i+len;//计算j
			for(int k=1;k<=j-i+1;k++) dp[i][j]=min(dp[i][j],dp[i+1][i+k-1]+(k-1)*x[i]+dp[i+k][j]+k*(sum[j]-sum[i+k-1]));
		}
	}
	printf("Case #%d: %d\n",++T,dp[1][n]);
}
void init(){
	sum[0]=0;
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		init();
		for(int i=1;i<=n;i++) scanf("%d",&x[i]);
		minval();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Hc_Soap/article/details/107455783