1. 程式人生 > >NYOJ746 整數劃分(四)(深搜DFS,區間DP)

NYOJ746 整數劃分(四)(深搜DFS,區間DP)

題目;

整數劃分(四)

時間限制: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;
}