整数划分
题目描述
有N堆石子排成一排(n<=100),现要将石子有次序地合并成一堆,规定每次只能选相邻的两堆合并成一堆,并将新的一堆的石子数,记为改次合并的得分,编一程序,由文件读入堆数n及每堆石子数(<=200);
(1)选择一种合并石子的方案,使得做n-1次合并,得分的总和最少
(2)选择一种合并石子的方案,使得做n-1次合并,得分的总和最多
输入格式
第一行为石子堆数n 第二行为每堆石子数,每两个数之间用一空格分隔。
输出格式
从第1行为得分最小第二行是得分最大。
样例
1
199 2
171
19 9
拿合并石子的思想,长度就是数字长度,
前缀和为i到j间的数(如样例中s[2][3]指99)
断点为划分数-1;
f[i][j]第一维为长度,第二维为断点数量
f[i][j]=max(f[i][j],f[k][j-1]*s[k+1][i])
(f[k][j-1]表示1到k的数,断点为j-1)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
string a1;
long long int a[50];
long long int s[50][50];
long long int f[50][50];
long long int vis[50][50];
bool flag1=0,flag2=0;
void print (int i,int j){
if(j<0) return;
print(vis[i][j],j-1);
cout<<s[vis[i][j]+1][i]<<" ";
}
int main(){
int T;
cin>>T;
while(T--){
memset(a,0,sizeof(a));
memset(s,0,sizeof(s));
memset(f,0,sizeof(f));
cin>>a1;
cin>>m;
m--;
n=a1.length();
for(int i=1;i<=n;i++){
a[i]=a1[i-1]-'0';
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
s[i][j]=s[i][j-1]*10+a[j];
}
}
for(int i=1;i<=n;i++) f[i][0]=s[1][i];
for(int len=2;len<=n;len++){
for(int j=1;j<=m&&j<len;j++){
for(int k=1;k<len;k++){
f[len][j]=max(f[len][j],f[k][j-1]*s[k+1][len]);
if(f[len][j]==f[k][j-1]*s[k+1][len]){
vis[len][j]=k;
}
}
}
}
cout<<f[n][m]<<endl;
print(n,m);
cout<<endl;
}
}

浙公网安备 33010602011771号