一、題目:
給出一個數字(10,000~100,000,000),把這個數字拆分成4段,怎樣使得4段的乘積最小。比如12345拆分成1*2*3*45=270,
10000=1*00*0*0=0。
二、分析:
這是一個典型的DP問題,假設dp[i][j]表示分成i段,且字串指標移動到第j位時的最小乘積。 則顯然i<=j.
num[i][j]是數字中從第i個數字到第j個數字組成的數字。則可以得到DP的狀態方程:
dp[i-][j-k]表示當數字分成i-1段,且字串指標移動第j-k位時的狀態,因為(i-1)<=(j-k) ,所以要求k<=j-i+1。
由狀態方程很容易得出對應的結果:
| i\j |
1 |
2 |
3 |
4 |
5 |
| 1 |
1 |
12 |
123 |
1234 |
12345 |
| 2 |
- |
2 |
23 |
234 |
2345 |
| 3 |
- |
- |
6 |
68 |
690 |
| 4 |
- |
- |
- |
24 |
270 |
| 5 |
- |
- |
- |
- |
120 |
本題是分成4段,很容易得到dp[4][5] 輸出結果是:270.
三、代碼如下:
#include<stdio.h>#define MAXN ((1<<31)-1) //極大值 char A[10];int num[10][10];int dp[10][10]; //將對應字串的制定位置轉換為整數。 int getInt(int i,int j){ int temp=0,k; for(k=i-1;k<=j-1;k++) temp=temp*10+(A[k]-'0'); return temp;}int main(){ int i,j,k,len,temp,min; while(scanf("%s",A)!=EOF) { k=0; while(A[k]!='\0') k++; len=k; //獲得字串的長度 if(len<5||len>9) return 0; //長度必須是5到9 for(i=1;i<=len;i++) for(j=i;j<=len;j++) num[i][j]=getInt(i,j); for(j=1;j<=len;j++) dp[1][j]=getInt(1,j); //初始化分割為1時的狀態 for(i=2;i<=len;i++) for(j=i;j<=len;j++) { min=MAXN; for(k=1;k<=j-i+1;k++) { temp=dp[i-1][j-k]*num[j-k+1][j]; if(temp<min) min=temp; } dp[i][j]=min; if(j!=len) printf("%d ",dp[i][j]); else printf("%d\n",dp[i][j]); } printf("分成4段時,最小的分割方法是:%d\n",dp[4][len]); } return 0; }