1. 程式人生 > >you are the one(區間dp)

you are the one(區間dp)

ttr java 第一個 meet void esp ++ cau there

傳送門

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)

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; }

you are the one(區間dp)