zafu 1461 (DP)
http://info.zjfc.edu.cn/acm/problemDetail.aspx?pid=1461
Simple Game
时间限制 : 1000 ms 内存限制 : 32 MB
提交次数 : 63 通过次数 : 31
题目描述
有n堆沙子,第i堆沙子的重量是W(i),有一个小游戏是要把这n堆沙子给合并成一堆沙子。
每次只能将相邻两堆沙子合并为一堆沙子,合并两堆沙子为一堆沙子的体能消耗为两堆沙子的重量之和
。聪明的你能不能告诉我,把n堆沙子给合并成一堆沙子,最少需要消费多少体力呢。 举个例子:
假设有4堆沙子,重量分别为1、2、3、4,第一次合并两堆沙子的时候,可以合并重量为1、2或者
重量为2、3或者重量为3、4的两堆沙子,因为这些堆沙子是相邻的。假设第一次合并的是第2、3堆
沙子(消费体力2+3=5),那么第一次合并后3堆沙子的重量序列为1、5、4。第二次合并两堆沙子的时候
,可以合并重量为1、5的两堆沙子或者重量为5、4的两堆沙子,因为它们是相邻的。假设第二次合并的是
后面两堆沙子(消费体力5+4=9),则合并后剩余2堆的沙子的重量序列为1、9。最后将剩余两堆沙子合
并(消费体力1+9=10)。这个过程中共消费体力5+9+10=24。 以上例子只是说明合并沙堆的过程中,
并不是最优方案。
输入描述
本题包含多组测试数据,在每组测试数据中:第一行包含一个正整数n(小于等于100),
接下来是第二行是n个整数表示n堆沙子的重量(小于等于100)。
输出描述
对于每组数据,输出一个数,表示将输入n堆石子合并为一堆石子消费的最少体力。
样例输入
3
6 7 8
3
6 8 7
样例输出
34
35
来源
浙江农林大学第十届电脑节程序设计大赛正式赛
/*
校赛时用贪心写WA,想到DP,但不会转移方程,DP该练了
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j])+sum[i][j];
考虑问题可以按递归着推,之后反向写方程就行了
*/
#include <stdio.h>
#define MAX 999999999
int dp[105][105];
int sum[105][105];
int min(int a,int b)
{
return a<b?a:b;
}
int main()
{
int i,j,k,n;
int a[105];
while(scanf("%d",&n)!=EOF)
{
sum[1][0]=0;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[1][i]=sum[1][i-1]+a[i];
}
//
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
dp[i][j]=MAX;
}
dp[i][i]=0;
}
for(i=2;i<=n;i++)
{
sum[i][i]=a[i];
for(j=i+1;j<=n;j++)
{
sum[i][j]=sum[1][j]-sum[1][i-1];
}
}
//关键代码
for(i=n;i>=1;i--)
{
for(k=i;k<=n;k++)
{
for(j=k+1;j<=n;j++)
{
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j])+sum[i][j];
}
}
}
printf("%d\n",dp[1][n]);
}
return 0;
}

浙公网安备 33010602011771号