Competition Description:
This year is the "2000 - World Year of Mathematics" determined by the International Mathematics Federation, which coincides with the 90th anniversary of the birth of Mr. Hua Luogeng, a famous mathematician in China. In Mr. Hua Luogeng's hometown, Jintan, Jiangsu Province, he organized a unique mathematical intelligence contest. A good friend of yours, XZ, was also lucky to participate. In the event, the host gave all the participants such a topic:
There is a number string with length of N. The players are required to divide it into K+1 parts by using K multiplier signs, and find out a division method, so that the product of K+1 parts can be maximized. At the same time, in order to help the contestants understand the topic correctly, the host also cited the following example:
There is a numeric string: 312. When N=3 and K=1, there are two ways to divide it:
1) 3*12=36
2) 31*2=62
At this time, the result that meets the requirements of the title is: 31*2=62
Now, please help your good friend XZ design a program to get the right answer.
Input:
There are two lines of input:
There are two natural numbers N and K in the first row (6 < N < 40, 1 < K < 6)
The second line is a number string of length N.
Output:
The maximum product (a natural number) obtained by the output is within the range of long data.
Sample input:
4 2
1231
Sample output:
62
Source of title:
NOIP2000
Idea 1: Recursion
The author's own ideas.
At first, I didn't notice using dynamic programming to solve the problem, so I simulated manual algorithm with program, exhaustively enumerated all possibilities, multiplied the given number series by segments, and got the maximum product. There is a problem in Test4, but I haven't found it. I put the code here and hope God can help me.
#include<iostream> #include<string.h> #include<stdlib.h> using namespace std; int GetSubNum(int num,int N,int start,int len);//start from num, the number len in length void CalStart(int start[],int len[],int K); //Calculate start arrays from len arrays void Fun(int i,int num,int N,int K,int start[],int len[],int pos[],long long &rst);//Recursive function int main() { int N,K; long long rst=0; cin>>N>>K; char str[45]; cin>>str; int num=atoi(str); int start[7]={0}; //The starting position of each segment of the number int len[7]; //Length of each digit for(int i=0;i<7;i++) len[i]=1; int pos[6]; //the position of "*" pos[0]=0; //Let the first multiplication sign start at position 0. Fun(0,num,N,K,start,len,pos,rst); //Recursive computation cout<<rst<<endl; return 0; } int GetSubNum(int num,int N,int start,int len) { if(start<0||start>=N) return -1; if(len>N||start+len>N) return -1; int result=num; int left=start; int right=N-start-len; int a=1; for(int i=0;i<N-left;i++) { a*=10; } result%=a; a=1; for(int i=0;i<right;i++) { a*=10; } result/=a; return result; } void CalStart(int start[],int len[],int K) { for(int i=1;i<K+1;i++) { start[i]=start[i-1]+len[i-1]; } } void Fun(int i,int num,int N,int K,int start[],int len[],int pos[],long long &rst) { if(i==K-1) { //to avoid special situation : i==0,i-1 not exist int temp; if(i==0) temp=-1; else temp=pos[i-1]; //** for(pos[i]=temp+1;pos[i]<N-1;pos[i]++) { int len1=0;//Sum of len[0~(k-1)] for(int j=0;j<K+1;j++) { if(j==0) { len[j]=pos[j]+1; len1+=len[j]; } else if(j==K) len[j]=N-len1; else { len[j]=pos[j]-pos[j-1]; len1+=len[j]; } } //calc start[] start[0]=0; CalStart(start,len,K); //calc the result of this situation long long ans=1; for(int j=0;j<K+1;j++) //K+1 block multiplication { int temp=GetSubNum(num,N,start[j],len[j]); //cout<<"temp="<<temp<<endl; ans*=temp; //cout<<"ans="<<ans<<endl; } if(ans>rst) { rst=ans; } } } else { //to avoid special situation : i==0,i-1 not exist int temp; if(i==0) temp=-1; else temp=pos[i-1]; //** for(pos[i]=temp+1;pos[i]<N-1-(K-1-i);pos[i]++) { int ii=i+1;//pos[ii] for recursion Fun(ii,num,N,K,start,len,pos,rst); } } }
Idea 2: Dynamic Planning
The idea of dynamic programming makes the code very simple and efficient. Here I refer to other people's blogs, links in the following reference materials, thank you very much.
#include <stdio.h> #include <stdlib.h> typedef unsigned long long bignum; bignum f[41][31]; bignum num[41][41]; char str[42]; #define max(a, b) ((a)>(b)?(a):(b)) int main(int argc, char **argv) { int i, j, l; int n, k; scanf("%d%d", &n, &k); scanf("%s", &str[1]); for(i = 1; i <= n; i++) { for(j = i; j <= n; j++) { num[i][j] = num[i][j - 1] * 10 + str[j] - '0'; } } for(i = 1; i <= n; i++) { f[i][0] = num[1][i]; } for(j = 1; j <= k; j++) //"*" quantity { for(i = 2; i <= n; i++) //The first i digits { for(l = 1; l < i; l++)//Find the maximum value of the first I digits obtained by using J multipliers, and mark it as f[i][j]. { f[i][j] = max(f[i][j], f[l][j - 1] * num[l + 1][i]); } } } printf("%I64d\n", f[n][k]); return 0; }
Conclusion:
When starting to solve a problem, we must be slow at the beginning. The direction of solving the problem is very important. The direction is right and the result is twice the result with half the effort.
Reference material:
http://www.cnblogs.com/yylogo/archive/2011/08/06/NOIP-2000-3.html