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
额,这道题是我做过的感觉是目前为止最难的动态规划的题,区间dp里比较难的。
想详细讲一下状态量和状态转移方程,加深印象
**状态:**f(i,j)—>在只考虑i到j的范围里的最小的屌丝值的总和(所有我们的答案当然是f(1,n))。
主要是也是关键,状态该怎么转移
假设我们有6个人,值依次为:
1 2 3 2 4 1
假设我们已经得出所有区间长度为1到5的状态量(长度为6的区间当然就是f(1,6)啦)
区间dp的一个重要的思想是分割区间,对于这道题我们该怎么分割区间,分割的标准是什么。
这里我们看第一个屌丝(也就是最左边的),针对这个屌丝我们来讨论,那么这个屌丝可能出场的顺序的可能是1到6(显然),
那么假设这个屌丝是第3个出来的,那么首左数第二个和第三个必须先出去,才能轮到这个屌丝。
那么好假设1到3的屌丝已经上台了,那么对于4到6的屌丝不管他们在以什么顺序上台,那么对于第四个屌丝值至少已经×3,第五个屌丝值至少已经×3,第六个也是,那么就变成4到6的的屌丝的和在乘以3(就是2×3+4×3+1×3==(2+4+1)*3这个对编程有简化作用),接着4到6是按照什么顺序出的,就只要加上f(4,6)就可以了
那么*转移方程就是:f(i,j)=min{ f(i+1,i+k-1)+a(i)*(k-1)+sum(i+k,j)*k+f(i+k,j) | k 是在i到j长度的其中一个值}表示a(i)是第k个出场的。
代码:
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
int t=sc.nextInt();
int n;
int c=1;
while((t--)>0)
{
n=sc.nextInt();
int a[]=new int[n+1];
int sum[]=new int[n+1];
for(int i=1;i<=n;i++)
{
a[i]=sc.nextInt();
sum[i]=sum[i-1]+a[i];
}
int dp[][]=new int[n+2][n+2];
for(int len=2;len<=n;len++)
{
for(int i=1;i+len<=n+1;i++)
{
int j=len+i-1;
dp[i][j]=Integer.MAX_VALUE;
for(int k=1;k<=len;k++)
{
dp[i][j]=Math.min(dp[i][j], dp[i+1][i+k-1]+dp[i+k][j]+(k-1)*a[i]+k*(sum[j]-sum[i+k-1]));//核心代码
}
}
}
System.out.println("Case #"+(c++)+": "+dp[1][n]);
}
}
}