社区讨论

直线型石子合并的问题

学术版参与者 4已保存回复 9

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
9 条
当前快照
1 份
快照标识符
@mi86iui6
此快照首次捕获于
2025/11/21 09:26
4 个月前
此快照最后确认于
2025/11/21 09:26
4 个月前
查看原帖
题目应该都知道吧
题目描述
在一条直线上有n(n<=100)堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。求把所有石子合并成一堆的最小花费。
输入
第1行为石子堆数n。
第2行为每堆石子数,每两个数之间用一个空格隔开。
输出
最小的得分总和。
样例输入
5
1 2 3 4 5
样例输出
33
一本通上的代码是
CPP
cin>>n;
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		s[i]=s[i-1]+x;
	}
	for(int i=n+1;i<=2*n-1;i++)
	s[i]=s[i-n];
	memset(f,127,sizeof(f));//原来是127/3
	for(int i=1;i<=2*n-1;i++)f[i][i]=0;
	
	for(int i=n-1;i>=1;i--)
	for(int j=i+1;j<=n;j++)
	for(int k=i;k<=j-1;k++)
	f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
	cout<<f[1][n];
而网上代码是
CPP
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
//#define inf 1<<20
const int maxn=210;
int n,a[maxn]; 
int  dp[maxn][maxn];//dp[i][j]表示从第i堆到第j堆合并的代价
int  sum[maxn][maxn];//表示石头的数量 
int main()
{
	ios::sync_with_stdio(0);
	while(cin>>n)
	{
		for(int i=1;i<=n;i++)
		cin>>a[i];
		memset(sum,0,sizeof(sum));
		//fill(dp[0],dp[0]+n*n,inf);//错误 
		fill(dp[0],dp[0]+maxn*maxn,inf);//fill填充量必须是常数 
 
		for(int i=1;i<=n;i++)
		sum[i][i]=a[i],dp[i][i]=0;
		
		for(int len=1;len<n;len++){//区间长度 
			for(int i=1;i<=n&&i+len<=n;i++){//区间起点 
				int j=i+len;//区间终点
				for(int k=i;k<=j;k++)//用k来表示分割区间 
				{
					sum[i][j]=sum[i][k]+sum[k+1][j];
					dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[i][j]);
				 } 
			}
		}
		cout<<dp[1][n]<<endl;
	}
	return 0;
} 
为什么两者的i循环不一样? 一本通是逆序,而该代码是顺序
倘若用一本通的代码,改成顺序,那么答案完全错误
为什么?请赐教

回复

9 条回复,欢迎继续交流。

正在加载回复...