NYOJ746 整數劃分(四)(深搜DFS,區間DP)
阿新 • • 發佈:2019-02-07
題目;
整數劃分(四)
時間限制:1000 ms | 記憶體限制:65535 KB 難度:3- 描述
-
暑假來了,hrdv 又要留學校在參加ACM集訓了,集訓的生活非常Happy(ps:你懂得),可是他最近遇到了一個難題,讓他百思不得其解,他非常鬱悶。。親愛的你能幫幫他嗎?
問題是我們經常見到的整數劃分,給出兩個整數 n , m ,要求在 n 中加入m - 1 個乘號,將n分成m段,求出這m段的最大乘積
- 輸入
- 第一行是一個整數T,表示有T組測試資料
接下來T行,每行有兩個正整數 n,m ( 1<= n < 10^19, 0 < m <= n的位數); - 輸出
- 輸出每組測試樣例結果為一個整數佔一行
- 樣例輸入
-
2 111 2 1111 2
- 樣例輸出
-
11 121
- 來源
- 經典題目
思路:
搜尋的思路就不說了,先初始化一下每一個區間的值,然後再相乘就好。
DP的思路是先預處理出每一個區間的值。
然後用dp[i][j]表示把0~i這個區間劃分成j段所能獲得的最大乘積。
則:
dp[i][j]=max(dp[i][j],dp[k][j-1]*sum[k+1][i])
程式碼1(dfs):
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <string> #include <iostream> #include <stack> #include <queue> #include <vector> #include <algorithm> #define mem(a,b) memset(a,b,sizeof(a)) #define N 100000+10 #define M 10000+20 #define MOD 1000000000+7 #define inf 0x3f3f3f3f #define ll long long using namespace std; char s[100]; ll sum[100][100]; ll len,maxx,n,m; void dfs(ll i,ll ans,ll step) { if(step==m) { maxx=max(ans,maxx); return; } for(ll j=1; j<=len-m+1; j++)//i和j是區間 if(i+j<=len) dfs(i+j,ans*sum[i+1][i+j],step+1); } int main() { ll t; scanf("%lld",&t); while(t--) { maxx=0; scanf("%s%lld",s+1,&m); len=strlen(s+1); for(ll i=1; i<=len; i++) { sum[i][i]=s[i]-'0'; for(ll j=i+1; j<=len; j++) sum[i][j]=sum[i][j-1]*10+s[j]-'0'; } dfs(0,1,0); printf("%lld\n",maxx); } return 0; }
程式碼2(DP):
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <string> #include <iostream> #include <stack> #include <queue> #include <vector> #include <algorithm> #define mem(a,b) memset(a,b,sizeof(a)) #define N 100000+10 #define M 10000+20 #define MOD 1000000000+7 #define inf 0x3f3f3f3f #define ll long long using namespace std; char s[100]; ll sum[100][100],dp[100][100]; ll n,m; int main() { ll t; scanf("%lld",&t); while(t--) { mem(dp,0); scanf("%s%lld",s,&m); n=strlen(s); for(ll i=0; i<n; i++) { sum[i][i]=s[i]-'0'; for(ll j=i+1; j<n; j++) sum[i][j]=sum[i][j-1]*10+s[j]-'0'; } for(ll i=0; i<n; i++) { dp[i][1]=sum[0][i]; for(ll j=2; j<=m; j++) //列舉段數 for(ll k=j-2; k<i; k++) dp[i][j]=max(dp[i][j],dp[k][j-1]*sum[k+1][i]); } printf("%lld\n",dp[n-1][m]); } return 0; }