1. 程式人生 > 其它 >題解:乘積最大

題解:乘積最大

目錄

題目

題目描述

今年是國際數學聯盟確定的“ 2000 ――世界數學年”,又恰逢我國著名數學家華羅庚先生誕辰 90 週年。在華羅庚先生的家鄉江蘇金壇,組織了一場別開生面的數學智力競賽的活動,你的一個好朋友 XZ 也有幸得以參加。活動中,主持人給所有參加活動的選手出了這樣一道題目:
設有一個長度為N的數字串,要求選手使用K個乘號將它分成K+1個部分,找出一種分法,使得這K+1個部分的乘積能夠為最大。
同時,為了幫助選手能夠正確理解題意,主持人還舉了如下的一個例子:
有一個數字串:312, 當 N=3,K=1時會有以下兩種分法:

3×12=36 
31×2=62 

這時,符合題目要求的結果是: 31×2=62
現在,請你幫助你的好朋友 XZ 設計一個程式,求得正確的答案。

輸入格式

程式的輸入共有兩行:
第一行共有2個自然數 N,K(6≤N≤40,1≤K≤6)
第二行是一個長度為N的數字串。

輸出格式

結果顯示在螢幕上,相對於輸入,應輸出所求得的最大乘積(一個自然數)。

輸入輸出樣例

輸入
4  2
1231
輸出
62

解析

記憶化搜尋,dfs(x,y),x表示第一個乘號出現的位置,y表示還剩多少個乘號。

注意幾個地方

1、計算
long long sum(long long x,long long y) {
    long long ans = 0;
    for(int i = x; i <= y; i++) {
	    ans = ans * 10;
	    ans = ans + a[i];
    }
    return ans;
}

這個用於計算分出來的段組成的數的值,注意一定要先乘十再累加

2、狀態轉移方程
for(int i = x + 1; i  <= N; i++) {
	    ans = max(ans,dfs(i,y - 1) * sum(x,i - 1));
    }

列舉乘號位置,後面繼續搜,前面算數

3、邊界條件
if(dp[x][y]) return dp[x][y];//已經搜過了
if(N - x < y) return 0;//乘號比數多
if(y == 0) return sum(x,N);//乘號用完了
4、高精度

正常來說,這道題需要使用高精,但是重在思路,所以我並沒有花時間去寫。。

程式碼

#include<bits/stdc++.h>
using namespace std;
int N,K;
long long a[10001];
long long dp[101][1001];
long long sum(long long x,long long y) {
    long long ans = 0;
    for(int i = x; i <= y; i++) {
	    ans = ans * 10;
	    ans = ans + a[i];
    }
    return ans;
}
long long dfs(int x,int y) {
    long long ans = 0;
    if(dp[x][y]) return dp[x][y];
    if(N - x < y) return 0;
    if(y == 0) return sum(x,N);
    for(int i = x + 1; i  <= N; i++) {
	    ans = max(ans,dfs(i,y - 1) * sum(x,i - 1));
    }
    return dp[x][y] = ans;
}
int main() {
    scanf("%d %d" ,&N,&K);
    for(int i = 1; i <= N; i++) {
	    scanf("%1lld" ,&a[i]);
    }
    printf("%lld" ,dfs(1,K));
    return 0;
}