合唱團 動態規劃

合唱團

問題描述:

有 n 個學生站成一排,每個學生有一個能力值,牛牛想從這 n 個學生中按照順序選取 k 名學生,要求相鄰兩個學生的位置編號的差不超過 d,使得這 k 個學生的能力值的乘積最大,你能返回最大的乘積嗎?

dp[i][j]表示 依次選好第i個學生時 他在隊伍裏排第j名能力值乘積最大爲多少 應該是i>=j
dp[i][j] = arr[i] * max(dp[i-1][j-di]);
邊界條件 dp[0][j]=1;
但是因爲每個學生的能力有正有負,所以如果arr[i]爲負值,那麼dp[i][j] = arr[i] * min(dp[i-1][j-di]);
我們可以
用dp1[i][j]表示依次選好第i個學生時 他在隊伍裏排第j名能力值乘積最大爲多少
用dp2[i][j]表示依次選好第i個學生時 他在隊伍裏排第j名能力值乘積最小爲多少

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long int 
const ll maxn = 55;
ll arr[maxn];
ll dp1[maxn][maxn];		//存最大值 
ll dp2[maxn][maxn];		//存最小值 
int main()
{
	ll n;								//n個學生 
	while(cin>>n)
	{
		for(ll i=1;i<=n;++i)
		{
			cin>>arr[i];				//每個學生的能力值有正有負 
		}
		ll k,d;	//k個學生,編號差值不超過d 
		cin>>k>>d;
		memset(dp1,0,sizeof(dp1));
		memset(dp2,0,sizeof(dp2));
		for(ll i=0;i<=n;++i)
		{
			dp1[0][i]=1;
			dp2[0][i]=1; 
		}
		
		for(ll i=1;i<=k;++i)
		{
			for(ll j=1;j<=n;++j)
			{
				if(i>j) continue;				//選好了I個人,他不可能在原來的隊伍 
				ll num1 = -1<<30;
				ll num2 = 1<<30;
				for(int m=1;m<=d;++m)
				{
					if(j-m<0) break;
					num1=max(num1,dp1[i-1][j-m]);
					num2=min(num2,dp2[i-1][j-m]);
				}
				dp1[i][j] =max(num2 * arr[j], num1 * arr[j]);
				dp2[i][j] =min(num2 * arr[j], num1 * arr[j]); 
			}
		}
		ll ans = -1<<30;
//		for(int i=0;i<=k;++i)
//		{
//			for(int j=1;j<=n;++j)
//			{
//				cout<<dp1[i][j]<<" ";
//			}
//			cout<<endl;
//		} 
		for(ll i=k;i<=n;++i)
		{
			ans = max(ans,dp1[k][i]);
		}
		cout<<ans<<endl;
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章