you are the one(區間dp)
阿新 • • 發佈:2017-07-12
ttr java 第一個 meet void esp ++ cau there
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)
Sample Input
2
5
1
2
3
4
5
5
5
4
3
2
2
傳送門
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
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 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)