简介
青岛某高校,信安专业算法课程第二次课堂展示
设I是一个n位的十进制整数。如果将I划分为k段,则可得到k个整数。这k个整数的乘积称为I的一个k乘积。试设计一个算法,对于给定的I和k,求出I的最大k乘积。
当n=3,k=2时,给定数字串312
此时要将312三个整数划分为2段,需要在数字串的某个合法位置添加一个乘号。
将一个n位整数划分为k段,相当于在n段数字中合法的位置中加入k-1个乘号。
如果暴力的枚举乘号出现的位置,该问题的时间复杂度应该是O((n-1)!),时间复杂度太高,因此考虑动态规划的思路解决该问题。
f[i][j] 表示在前i个数字当中插入j个合法乘号的最大值。
m[i][j] 表示在数字串从i到j位置的数字组成数字的值的大小。
举例:当I=312时,m[1][1]=3,m[1][2]=31,m[2][3]=12…
用 f(i,j) 表示在前i个数字中插入j个乘号得到的最优解,则f(i,j)=f(t,j-1)*m[t+1][i]
此时的f(t,j-1)必为子问题的最优解。
反证法:
假设f(t,j-1)不是子问题的最优解,则一定存在一个e(t,j-1)>f(t,j-1)。
此时,在不等式的左右两边同时乘上m[t+1][i]得到:
e(t,j-1)*m[t+1][i]>f(t,j-1)*m[t+1][i]=f(i,j)
与前提相矛盾,于是得证f(t,j-1)是原问题的最优解。
f [ i ] [ j ] = { n u m [ 1 ] [ i ] j=0 m a x ( f [ t ] [ j − 1 ] ∗ n u m [ t + 1 ] [ i ] ) j>0,1<=t0,1<=tf[i][j]={num[1][i]max(f[t][j−1]∗num[t+1][i])j=0j>0,1<=t
将n个数字划分为k段(即在n个数字中插入k-1个乘号),依次遍历将前t位划分为k-1段的最优解并乘上其余位数组成的十进制数的数值的最大值存放在f[t][k-1]当中,最终输出f[n][k]即为最优解。
关键代码:
for(int i=1;i<=n;i++){ //枚举处理多少个数字
for(int j=1;j<=k;j++){ //枚举插入多少个乘号
for(int t=1;t<i;t++){ //枚举最后乘号的乘号插入哪里(将前多少个数字划为一类)
f[i][j]=max(f[i][j],f[t][j-1]*num[t+1][i]);
}
}
}
思路分析:
int z=n;
for(int i=n;i>=1;i--){
for(int j=k;j>=1;j--){
o=s.substr(d[i][j],n-d[i][j]);
int x=n-d[i][j];
if(i==z){
cout<<o;
}else{
if(o!="")
cout<<"*"<<o;
}
i-=x;
n-=x;
}
}
o=s.substr(0,n);
if(o!="")
cout<<"*"<<o;
printf("=%d\n",f[c][e]);
#include
using namespace std;
const int N=1010;
int f[N][N],num[N][N],a[N];
int d[N][N];
int ans[N];
int cnt;
int n,k;
int main(){
cin>>n>>k;
k--;
string s;
int c,e;
c=n,e=k;
cin>>s;
for(int i=1;i<=s.size();i++) a[i]=s[i-1]-'0';
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
num[i][j]=num[i][j-1]*10+a[j];
}
}
for(int i=1;i<=n;i++) f[i][0]=num[1][i]; //处理边界
for(int i=1;i<=n;i++){ //枚举处理多少个数字
for(int j=1;j<=k;j++){ //枚举插入多少个乘号
for(int t=1;t<i;t++){ //枚举最后乘号的乘号插入哪里(将前多少个数字划为一类)
if(f[t][j-1]*num[t+1][i]>f[i][j]) d[i][j]=t;
f[i][j]=max(f[i][j],f[t][j-1]*num[t+1][i]);
}
}
}
printf("最大值:%d\n",f[n][k]);
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
printf("%d ",d[i][j]);
}
printf("\n");
}
string o,p,q;
printf("表达式:");
int z=n;
for(int i=n;i>=1;i--){
for(int j=k;j>=1;j--){
o=s.substr(d[i][j],n-d[i][j]);
int x=n-d[i][j];
if(i==z){
cout<<o;
}else{
if(o!="")
cout<<"*"<<o;
}
i-=x;
n-=x;
}
}
o=s.substr(0,n);
if(o!="")
cout<<"*"<<o;
printf("=%d\n",f[c][e]);
for(int i=1;i<=c;i++){
for(int j=0;j<=e;j++){
printf("%d ",f[i][j]);
}
printf("\n");
}
return 0;
}