社区讨论
直线型石子合并的问题
学术版参与者 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
一本通上的代码是
CPPcin>>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 条回复,欢迎继续交流。
正在加载回复...