Time Limit: 1000MS | Memory Limit: 65536K | |||
Total Submissions: 96 | Accepted: 48 |
Description
在操场上沿一直线排列着
n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的两堆石子合并成新的一堆,
并将新的一堆石子数记为该次合并的得分。允许在第一次合并前对调一次相邻两堆石子的次序。
计算在上述条件下将n堆石子合并成一堆的最小得分。
Input
输入数据共有二行,其中,第1行是石子堆数n≤100;
第2行是顺序排列的各堆石子数(≤20),每两个数之间用空格分隔。
Output
输出合并的最小得分。
Sample Input
3 2 5 1
Sample Outpu
11
分析:设sum[i]为前i个石子的总分,dp[i][j]为i到j之间最小得分。
则可得状态转移方程dp[i][j]=min{dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]};
枚举对调位置,找出最小得分。
代码:
1 #include <stdio.h>
2 #include <algorithm>
3
4 using namespace std;
5 #define MAX 0x7fffffff/2
6 int dp[110][110], n, a[110], w[110], ans;
7
8 int dpp()
9 {
10 int i, j, l, k;
11 w[0]=0;
12
13 for(i=0;i<101;i++)
14 for(j=0;j<101;j++)
15 dp[i][j]=MAX;
16 for(i=1;i<=n;i++){
17 w[i]=w[i-1]+a[i];
18 dp[i][i]=0;
19 }
20 for(i=n-1;i>=1;i--)
21 {
22 for(l=1;l<=n-i;l++)
23 {
24 j=l+i;
25 for(k=i;k<j;k++)
26 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+w[j]-w[i-1]);
27 }
28 }
29 if(ans>dp[1][n])
30 ans=dp[1][n];
31 return ans;
32 }
33
34 main()
35 {
36 int i, j;
37 scanf("%d",&n);
38 for(i=1;i<=n;i++) scanf("%d",&a[i]);
39 ans=MAX;
40 dpp();
41 for(i=1;i<n;i++)
42 {
43 swap(a[i],a[i+1]);
44 dpp();
45 swap(a[i],a[i+1]);
46 }
47 printf("%d\n",ans);
48 }
时间: 2025-01-05 04:03:29