You Are the One
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6711 Accepted Submission(s): 3341
The next n line are n integer D1-Dn means the value of diaosi of boys (0 <= Di <= 100)
本题大意:队列中有n个人,要求从1到n依次上台,每个人上台有一个unhappy值val,假设第i个人
第k个上台那么他所带来的unhappy值为(k - 1) * val[ i ],为了使得unhappy变得足够小,现在允许轮到一个人上台的时候让他进入一个窄巷,窄巷满足先进后出原则,问你通过这个窄巷调整上台顺序,让这n个人都上台后的最小unhappy值为多少。
本题思路:分析容易知道对于第i个人,他是否入栈,何时出栈都会影响到最后的分数,所以我们肯定是要枚举每个人的是否入栈和出入栈状况,我们肯定会枚举每个i,容易想到区间dp,我们用dp[ i ][ j ]表示第 i 到 j 的人已经上台所花费的最小值(仅是i -> j,不考虑其他人),那么选择断点k,我们让i第k个上台,很容易知道它前面的 k - 1个人已经上台了,i第k各上台的花费为(k - 1) * val[ i ],他前面的人肯定是已经上台了的,那就是dp[i + 1][i + k - 1],第k + i ~ j 个人肯定在 i 之后,所以就有了子问题dp[k + i ][ j ],但是在计算这个子问题时肯定是把i + k当作第1个人的,所以在原问题上我们共把每个数多算了k 次,所以就可以得到状态转移方程dp[ i ][ j ] = (k - 1) * val[ i ] + dp[i + 1][i + k - 1] + dp[i + k][ j ] + (sum[ j ] - sum[i + k - 1]) * k。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 200 + 5, inf = 0x3f3f3f3f; 7 8 int val[maxn], sum[maxn], dp[maxn][maxn]; 9 int n; 10 11 int main() { 12 int t, _case = 0; 13 scanf("%d", &t); 14 while(t --) { 15 memset(dp, 0, sizeof dp); 16 scanf("%d", &n); 17 for(int i = 1; i <= n; i ++) { 18 scanf("%d", &val[i]); 19 sum[i] = sum[i - 1] + val[i]; 20 } 21 for(int len = 1; len < n; len ++) { 22 for(int i = 1; i + len <= n; i ++) { 23 int j = i + len; 24 dp[i][j] = inf; 25 for(int k = 1; k <= len + 1; k ++) { 26 dp[i][j] = min(dp[i][j], (k - 1) * val[i] + dp[i + 1][i + k - 1] + dp[i + k][j] + (sum[j] - sum[i + k - 1] ) * k); 27 } 28 } 29 } 30 printf("Case #%d: %d ", ++ _case, dp[1][n]); 31 } 32 return 0; 33 }