整数划分

来源:互联网 发布:羊毛刷批发淘宝网 编辑:程序博客网 时间:2024/05/16 02:01

问题描述 Description

如何把一个正整数 N(N 长度 <20)划分为 M(M>1)个部分,使这 N 个部分的乘积最大。NM 从键盘输入,输出最大值及一种划分方式。


输入描述 Input Description

第一行一个正整数 T(T10000) ,表示有 T 组数据。
接下来 T 行每行两个正整数 NM


输出描述 Output Description

对于每组数据
第一行输出最大值。
第二行输出划分方案,将 N 按顺序分成 M 个数输出,两个数之间用空格格开。


输入样例 Sample Input

1
199 2


输出样例 Sample Output

171
19 9


分析 I Think

fi,j 表示把 N 的前 i 位分成 j 个部分得到的最大值,ai,j 表示 N 从第 i 位到第 j 位的值,显然 fi,1=a1,i,考虑 fi,j ,我们可以先把 N 的前 k 为分成 j1 个部分,那么 fi,j=max{fk,j1ak+1,i}
输出方案就直接把前面的步骤倒过来就可以了,枚举 k 使得 fk,j1ak+1,i=fi,j


代码 Code

#include <cstring>#include <cstdio>#include <algorithm>using namespace std;typedef long long LL;char str[50];LL f[50][50];int length,m,t;LL a[50][50];void display(int,int);int main(){    scanf("%d",&t);    while( t-- ){        getchar();        scanf("%s%d",str+1,&m);        length = strlen(str+1);        for(int i=1;i<=length;++i)            a[i][i] = str[i]-'0';        for(int i=1;i<=length;++i)            for(int j=i+1;j<=length;++j)                a[i][j] = a[i][j-1]*10+a[j][j];        memset(f,0,sizeof f);        for(int i=1;i<=length;++i)            f[i][1] = a[1][i];        for(int i=2;i<=m;++i)            for(int j=i;j<=length;++j)                for(int k=i-1;k<j;++k)                    f[j][i] = max(f[j][i],f[k][i-1]*a[k+1][j]);        printf("%lld\n",f[length][m]);        display(length,m);        putchar(10);    }    return 0;}void display(int L,int M){    if(M == 1){        printf("%lld ",a[1][L]);        return ;    }    for(int k=M-1;k<L;++k)        if(f[L][M] == f[k][M-1]*a[k+1][L]){            display(k,M-1);            printf("%lld ",a[k+1][L]);            break;        }}
0 0