題解 P1018 【乘積最大】
阿新 • • 發佈:2018-11-07
題目連結:P1018 乘積最大
題面
今年是國際數學聯盟確定的“2000――世界數學年”,又恰逢我國著名數學家華羅庚先生誕辰90週年。在華羅庚先生的家鄉江蘇金壇,組織了一場別開生面的數學智力競賽的活動,你的一個好朋友XZ也有幸得以參加。活動中,主持人給所有參加活動的選手出了這樣一道題目:
設有一個長度為N的數字串,要求選手使用K個乘號將它分成K+1個部分,找出一種分法,使得這K+1個部分的乘積能夠為最大。
同時,為了幫助選手能夠正確理解題意,主持人還舉了如下的一個例子:
有一個數字串:312, 當N=3,K=1時會有以下兩種分法:
1) 3*12=36
2) 31*2=62
這時,符合題目要求的結果是:31*2=62
現在,請你幫助你的好朋友XZ設計一個程式,求得正確的答案。
題意
在一個長度為 N 的數字字串中加上 K 個乘號,使所得表示式值最大。
題解
前言: 洛谷資料加強了,用\(long long\)只有60分,我不講高精度乘法,只講如何解這道題。
由題中"可將它分成K+1個部分"得出,這是區間劃分類的題目。
要求找出區間最大值,因為乘號放在任何一個位置都不一定是等效的結果,有子結構。
要求最大值也就是間接性求最優子結構,子結構最優後的得出總體最優。符合無後效性。
題面題意分析後可以得出這是一道區間劃分DP題。
以加入的乘號數量作為劃分階段。
用 \(f[n][k]\)
預處理出 \(a[i][j]\) 表示原數字第 i 位到第 j 位組成的數字。
\(f[n][k] = max(f[i][k-1] * a[i+1][n],i∈[k,n))\)
程式碼(無高精度)
#include<bits/stdc++.h> using namespace std; long long dp[45][45],num[45][45]; bool tong[45][45]; int n,k; char ch[45]; inline void init() { cin >> n >> k; cin >> ch; for(int i = 0;i < n;i++) { for(int j = 0;j < n;j++) { if(i <= j) { for(int k = i;k <= j;k++) { num[i][j]*=10; num[i][j]+=ch[k]-'0'; } } } } } long long dfs(int n,int k) { if(k == 0) return num[0][n-1]; if(tong[n-1][k-1]) return dp[n-1][k-1]; for(int i = k;i < n;i++) dp[n-1][k-1] = max(dp[n-1][k-1],dfs(i,k-1)*num[i][n-1]); tong[n-1][k-1] = true; return dp[n-1][k-1]; } int main(int argc, char const *argv[]) { init(); cout << dfs(n,k); getchar();getchar();getchar(); return 0; }
有不懂的可以加我qq:2832853025