整数划分

题目描述
有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;
	}
	
}
posted @ 2024-02-17 18:54  shaoyufei  阅读(11)  评论(0)    收藏  举报