石子合并(一)

来源:互联网 发布:女生做春梦 知乎 编辑:程序博客网 时间:2024/05/21 09:28

题目

石子合并(一)

时间限制:1000 ms  |  内存限制:65535 KB
难度:3
描述
    有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。
输入
有多组测试数据,输入到文件结束。
每组测试数据第一行有一个整数n,表示有n堆石子。
接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开
输出
输出总代价的最小值,占单独的一行
样例输入
31 2 3713 7 8 16 21 4 18
样例输出
9239
来源
经典问题
上传者

TC_胡仁东



想法这题我不会,学长给了我一个算法(超厉害):

它的步骤如下:
设序列是stone[],从左往右,找一个满足stone[k-1] <= stone[k+1]的k,找到后合并stone[k]和stone[k-1],再从当前位置开始向左找最大的j,使其满足stone[j] > stone[k]+stone[k-1],插到j的后面就行。一直重复,直到只剩下一堆石子就可以了。在这个过程中,可以假设stone[-1]和stone[n]是正无穷的。

一开始我是按照他的思想来写代码的,可是遇到诸多问题,例如c语言中如何定义一个数为无穷大。在运算的过程中stone[-1]也给我带来了好多问题。

所以我将stone[-1]改成了stone[0],stone[n]改成了stone[n+1],也没有将它们俩定义为无穷大,而是设为各堆石子的和。


代码
 #include<stdio.h>
int main()
{
int stone[205],a,i,n,k,m,s=0,t=0,sum,max=0;
while(scanf("%d",&n) !=EOF){//直到文件结束
sum=0;//初始化
//将每堆石子的数量保存在数组中
for(i=1;i<n+1;i++)
{
    scanf("%d",&stone[i]);
}
//将数组的开头和结尾设置为最大值
for(i=1;i<n+1;i++){//找出数组中的最大值
  s=s+stone[i];
  }
    stone[0]=s;
    stone[n+1]=s;
do{
//从左向右寻找stone[i-1]<=stone[i+1]
   for(i=1;i<n+1;i++)
  {
      if(stone[i-1]<=stone[i+1])
     {
        k=i;//标记位置
        t=stone[i]+stone[i-1];//合并
        break;
    }
  }
   sum=sum+t;//合并石子所需的价值
//去掉合并的两个数,形成新数组,即将后面的数向前推两位
  for(i=k-1;i<n;i++){//此时数组有n个数
    stone[i]=stone[i+2];
 }
//从当前位置向左寻找第一个比t大的数,将t插到此数的后面
  for(i=k-2;i>=0;i--)
 {
     if(stone[i]>t)
     {
        m=i;//标记大于t的数的位置
        break; }
}
//形成新的数组
for(i=n;i>=m+2;i--){//空余出t的位置,即数组向后推一位,此时,数组应有n-1个数
   stone[i]=stone[i-1];
}
   stone[m+1]=t;//将t插入
   n--;
}while(n>1);
printf("%d\n",sum);
}
return 0;
}

 


原创粉丝点击