版权声明:个人笔记,仅供复习 https://blog.csdn.net/weixin_42373330/article/details/88932170
题目描述:
动态规划
1021 石子归并
1 秒 131,072 KB 20 分 3 级题
N堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
例如: 1 2 3 4,有不少合并方法
1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
输入
第1行:N(2 <= N <= 100)
第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)
输出
输出最小合并代价
输入样例
4
1
2
3
4
输出样例
19
分析:dp没思路,公式没写出来,不知道咋么做,下面用递归做的,写得有点头疼,过了部分样例
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define ll long long
//51nod -1021
const int N= 1e4+10;
int a[N];
ll f(int a[],int n,ll &value,ll &mx)//返回的是该段的总和,value表示该段的花费,mx是用来取最小的value的
{
if(n==2)
{
value =a[0]+a[1];
mx=value;
return a[0]+a[1];
}
else if(n==1)
{
value =0;
mx=0;
return a[0];
}
ll sum;
for(int i=1;i<=n-1;i++)//把该段分成两部分,i的位置表示分界的地方
{
int b[N],c[N];
for(int j=0;j<i;j++)
b[j]=a[j];
for(int j=i;j<n;j++)
c[j-i]=a[j];
ll value1,value2;
ll mx1,mx2;
sum= f(b,i,value1,mx1)+f(c,n-i,value2,mx2);
value=value1+value2+sum;//这段的value等于两端的value之和,加上最后的两端
if(i==1)
mx=sum+value1+value2;
else
mx=min(mx,value);
}
return sum;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
ll value,mx;
f(a,n,value,mx);
cout<<mx<<endl;
return 0;
}
dp方法
公式:dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
dp[i][j]表示第i堆到第j堆(含i,j)合并成一堆所需的最小代价
#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define ll long long
const int mod= 1000000007;
const int N=1e6+10;
int n;
int a[110];
int sum[110];
int dp[110][110];
void f()
{
sum[0]=0;
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i];
}
int main()
{
memset(dp,0,sizeof(dp));
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
f();
int len;//表示长度,由2到n遍历
for(len=2;len<=n;len++)
{
for(int i=1;i<n;i++)
{
int j=i+len-1;
for(int k=i;k<j&&j<=n;k++)
{
if(dp[i][j]==0)
dp[i][j]=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1];
else
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
}
}
}
cout<<dp[1][n]<<endl;
return 0;
}