【dp】环形dp

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_42725189/article/details/102620707
  • 主要思路,拆环,设置特定状态进行dp(多次dp)

多次dp,断环+强连

  • 例题:一天有n小时,每天能花m小时睡觉,要花1h入睡(不回体力),睡着后回体力,每个时间点回不同体力,问体力最大值
  • 思路:dp[i][j][0/1]表示第i小时,已睡j小时,当前是否在睡。分两个初始状态dp,一个是第一个小时没有深度睡眠,dp[1][0][0]=0,dp[1][1][1]=0;
    代码
#include<bits/stdc++.h>
using namespace std;
int n,b,v[4000],dp[3][4000][3],mx;
int main()
{
	scanf("%d%d",&n,&b);
	for(int i=1;i<=n;i++)
	scanf("%d",&v[i]);
	memset(dp,-0x3f,sizeof(dp));
	dp[1][1][1]=0;dp[1][0][0]=0;
	mx=-1;
	for(int i=2;i<=n;i++)
	{
		for(int j=i>b?b:i;j>=0;j--)
		{
			if(j>0)
			dp[i&1][j][1]=dp[(i-1)&1][j-1][1]+v[i];
			if(j>0&&dp[(i-1)&1][j-1][0]>dp[i&1][j][1])
			dp[i&1][j][1]=dp[(i-1)&1][j-1][0];
			dp[i&1][j][0]=dp[(i-1)&1][j][0];
			if(dp[(i-1)&1][j][1]>dp[i&1][j][0])
			dp[i&1][j][0]=dp[(i-1)&1][j][1];
		}
	}
	if(dp[n&1][b][0]>mx)mx=dp[n&1][b][0];
	if(dp[n&1][b][1]>mx)mx=dp[n&1][b][1];
	memset(dp,0xcf,sizeof(dp));
	dp[1][1][1]=v[1];
	for(int i=2;i<=n;i++)
	{
		for(int j=b>i?i:b;j>=1;j--)
		{
			dp[i&1][j][0]=dp[(i-1)&1][j][0];
			dp[i&1][j][1]=dp[(i-1)&1][j-1][1]+v[i];
			if(dp[(i-1)&1][j-1][0]>dp[i&1][j][1])
			dp[i&1][j][1]=dp[(i-1)&1][j-1][0];
			if(dp[(i-1)&1][j][1]>dp[i&1][j][0])
			dp[i&1][j][0]=dp[(i-1)&1][j][1];
		}
	}
	if(dp[n&1][b][1]>mx)mx=dp[n&1][b][1];
	cout<<mx;
}

化环为链,复制相连

思路:如题
例题:环路运输
代码:

#include<bits/stdc++.h>
#define N 2000005
using namespace std;
int x[N],n,nn,l=1,r,pos[N],ans;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	scanf("%d",&x[i]),x[i+n]=x[i];
	nn=n+n;
	for(int i=1;i<=nn;i++)
	{
		while(l<=r&&i-pos[l]>n/2)++l;
		if(l<=r&&ans<x[pos[l]]+i-pos[l]+x[i])
		ans=x[pos[l]]+i-pos[l]+x[i];
		while(l<=r&&(i-pos[r]>n/2||x[pos[r]]+i-pos[r]<x[i]))--r;
		pos[++r]=i;
	}
	printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_42725189/article/details/102620707
DP
DP?