数字最小k分割(算法上机)

对于一个整数x,的最小k(分割次数)分割,是在(k<x的位数,x=123位数为3, x=0,位数为1),在位数-1个空格中选出k个空格将元数字分为k+1段,求其各段乘机之和最大的分割乘积。

(注意:对数字x的分割,对于任意分割位置两端必须有数字,即分割所在位置在数字之间,因为在数字两端相当于没有分割,并且任意数x的0,分割>他的k分割K>1<len(数字长度),

证明:

此时存在数字

数字:a..b..

a*10^x+b*10^y  > (a*(10^(x-y)) * b*10^y

 (a*(10^(x-y)) +1> (a*(10^(x-y)) 

显然是正确的.


如x=3456,k=2的分割有:

3 4 56 乘积为672

3 45 6 乘积为810

34 5 6 乘积为1020

因此最大的k分割为1020


思路比较明显

数字x,的k分割,相当于数字长度l=len(x) (len(x) 数字的位数) 再l内的k分割, 记为dp[l][k]

dp[l][k]=max(dp[j][k-1]*result[j+1][l])  { j>=1&&j<=l )

最后的结果为dp[len(x)][k]

比较直观,由于只是上机题只考虑x再unsigned int 范围内部,由于上述结论(数字的任意分割乘积小于自身因此结果不会超过unsigned long int)

如果x不是一个数字而是一个数字字符串串的话那么思想不变,加上大数就好了。

下面贴上代码: 

滚动数组,要注意计算顺序.

#include <stdio.h>
#include <string.h>
#define max_n 100
typedef unsigned long int ul;
ul x,kk;
ul dp[max_n]={0};
int calculate[max_n]={0};
ul cnt[8]={1,10,100,1000,10000,100000,1000000,10000000};
int getlength(ul num){
	int i=1;
	while(num>=cnt[i]){
		i++;
	}
	return i;
}
int getNum(ul num,int i,int j){
	int len=getlength(num);
	return	(num%cnt[len-i+1])/cnt[len-j];
}
ul max(ul a,ul b){
	return a>b?a:b;
}
int main(){
	int i,j,k;
	int len;
	scanf("%lu%lu",&x,&kk);
	len=getlength(x);
	for(i=1;i<=len;i++){	
		dp[i]=getNum(x,1,i);
	}
	for(i=1;i<=kk;i++){
		for(j=len;j>=i+1;j--){
			for(k=j-1;k>=i;k--){
                                if(calculate[j]==0||dp[j]<dp[k]*getNum(x,k+1,j)){
                                                dp[j]=dp[k]*getNum(x,k+1,j);
                                                calculate[j]=1;
                                }
			
                        }
		}
                memset(calculate,0,sizeof(calculate));
	}
        printf("%lu\n",dp[len]);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值