you are the one(区间dp)
传送门
You Are the One
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4042 Accepted Submission(s):
1876
Problem 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)
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 .
Sample Input
2
5
1
2
3
4
5
5
5
4
3
2
2
Sample Output
Case #1: 20
Case #2: 24
【题目大意】
n个人参加节目,每人都有一个屌丝值D,如果他第k个上场,那么他的不高兴值为(k-1)*D,因为他要等k-1个人。
节目有个小黑屋(是个栈,满足栈的性质)可以改变入场顺序。求最小不高兴值。
【思路】
区间dp。
现在上场的人的可能性有..栈顶的那个人,队伍中的那个人,队伍中的人进栈后,队首的那个人。
用dp[i][j]表示第i个人到第j个人的最小不高兴价值。
区间dp要进行区间合并,进行枚举断点k。
dp[i][j]由dp[i][k]和dp[k+1][j]转移而来。
可以第i--k个人先上舞台,k+1--j后上舞台。
也可以第k+1---j个人先上舞台,第i--k个人后上舞台,这就要求i--k这些人进栈,那么再上舞台的顺序就是原来的逆序,不高兴值预处理。
注意,对于dp[i][j]是个独立的区间,看成第i个就是这个区间的第一个进行处理。只需在合并时处理一下。
转移方程:
dp[i][j]=min(dp[i][j],min{dp[i][k]+dp[k+1][j]+(sum[j]-sum[k-1])*(k-i+1) ,dp[k+1][j]+v[i][k]+(sum[k]-sum[i-1])*(j-k) })
转移方程指的是在上述两种情况中寻找最小值,其中sum是因为我们在处理dp[i][j]时是将i看做第一个处理的,
如果说i--k个先进入,k+1--j后进入(第一种情况),k+1--j每个人前面多了k-i+1个人,所以要加上产生的不高兴值。
记忆化搜索也可做。
最大值0x7fffffff(7个f为2147483647,3个f五位数)。
【code】
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define inf 0x7fffffff int n,t,kas; int sum[110],v[110][110],dp[110][110],a[110]; void befr() { for(int i=1; i<=n; i++) for(int j=i-1; j>=1; j--) v[j][i]=v[j+1][i]+a[j]*(i-j); } int main() { scanf("%d",&t); while(t--) { memset(sum,0,sizeof(sum)); memset(v,0,sizeof(v)); scanf("%d",&n); for(int i=1; i<=n; i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } for(int i=0; i<=n; i++) for(int j=0; j<=n; j++) if(i!=j) dp[i][j]=inf; else dp[i][j]=0; befr(); for(int j=1; j<=n; j++) for(int i=j-1; i>=1; i--) for(int k=i; k<j; k++) { dp[i][j]=min(dp[i][j],min(dp[i][k]+dp[k+1][j]+(sum[j]-sum[k])*(k-i+1),dp[k+1][j]+v[i][k]+(sum[k]-sum[i-1])*(j-k))); } printf("Case #%d: %d\n",++kas, dp[1][n]); } return 0; }