区间dp


这是一道非常典型的区间dp

for(int i=2*n-1;i>=1;i--)
for(int j=i+1;j<=2*n;j++)
for(int k=i;k<j;k++)
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+a[i]*a[k+1]*a[j+1]);
int maxn=0;
for(int i=1;i<=n;i++)
maxn=max(f[i][i+n-1],maxn);


这个题就没有枚举中间变量k
而是向两边扩展的
对于每个区间终极状态老头不知道在左边还是右边
于是新加一维
dp[i][j][0]表示关完区间[i,j]的灯后老头在左边
反之 在右边

f[c][c][0]=f[c][c][1]=0;//瞬间被关(初始化)
  for(int l=2;l<=n;l++)
    for(int i=1;i+l-1<=n;i++)
      {
    int j=i+l-1;
    f[i][j][0]=min(f[i+1][j][0]+(a[i+1]-a[i])*(sum[i]+sum[n]-sum[j]),//继续走下去会更快吗?
               f[i+1][j][1]+(a[j]-a[i])*(sum[i]+sum[n]-sum[j]));//还是从j点折返回来会更快?(此时假设[i+1][j]被关,i亮,从j端点往回赶去关i)
//要注意的一点是sum[n]-(sum[j]-sum[i])是包括了i这一点的电能的,因为走过来的过程中灯i也会耗电
    f[i][j][1]=min(f[i][j-1][0]+(a[j]-a[i])*(sum[i-1]+sum[n]-sum[j-1]),//同上
               f[i][j-1][1]+(a[j]-a[j-1])*(sum[i-1]+sum[n]-sum[j-1]));
        }
  int ans=min(f[1][n][0],f[1][n][1]);


这个题和第一个题很类似,都是合并类型
最大最小就在另开一维数组

f[i][j][0]=max(f[i][j][0],f[i][k][0]+f[k+1][j][0]+s[j]-s[i-1]);
f[i][j][1]=min(f[i][j][1],f[i][k][1]+f[k+1][j][1]+s[j]-s[i-1]);

分析:

首先走过的雕像一定是连续的一段区间 并且最终一定在一段区间的两边

所以转移的过程 就没必要枚举中间变量 因为[L,R] 一定是从[L-1,R] 或者 [L,R+1] 转移过来

又因为时间太大 不能将时间放入dp维度中 所以换个思路 不妨将时间变为dp结果

dp[i][j][k][0] 表示区间[i,j]收集了k个雕像 并且最终在左端点 所花的最少时间

dp[i][j][k][1] 表示区间[i,j]收集了k个雕像 并且最终在右端点 所花的最少时间

读清题目!!!起点是固定的!!!!


#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

#define LL long long

using namespace std;

const int kN=205;
const int kInf=0x3f3f3f3f;

int n,l;
int x[2*kN],t[2*kN];
int f[2*kN][2*kN][kN][2];  
int ans;

int main(){
	scanf("%d%d",&n,&l);
	for(int i=1;i<=n;++i){
		scanf("%d",&x[i]);
		x[i+n+1]=x[i]+l;//将位置复制一份
	}
	for(int i=1;i<=n;++i){
		scanf("%d",&t[i]);
		t[i+n+1]=t[i];//将时间复制一份
	}
	memset(f,0x3f,sizeof f);
	t[n+1]=-kInf;x[n+1]=l;
    //n+1对应着起点
	for(int i=n+1;i<=(n<<1)+1;++i){
		for(int j=n+1;j&&i-j<=n;--j){
			f[j][i][0][0]=l-x[j];
			f[j][i][0][1]=x[i]-l;//初始化k=0的状态
		}
	}
	for(int i=n+1;i<=(n<<1)+1;++i){
		for(int j=n+1;j&&i-j<=n;--j){//保证区间<=n
			for(int k=1;k<=i-j;++k){
				f[j][i][k][0]=min(f[j][i][k][0],f[j+1][i][k][0]+(x[j+1]-x[j]));
				if(f[j+1][i][k-1][0]+x[j+1]-x[j]<=t[j])
					f[j][i][k][0]=min(f[j][i][k][0],f[j+1][i][k-1][0]+(x[j+1]-x[j]));
				
				f[j][i][k][0]=min(f[j][i][k][0],f[j+1][i][k][1]+(x[i]-x[j]));
				if(f[j+1][i][k-1][1]+x[i]-x[j]<=t[j])
					f[j][i][k][0]=min(f[j][i][k][0],f[j+1][i][k-1][1]+(x[i]-x[j]));
				
				f[j][i][k][1]=min(f[j][i][k][1],f[j][i-1][k][1]+(x[i]-x[i-1]));
				if(f[j][i-1][k-1][1]+x[i]-x[i-1]<=t[i])
					f[j][i][k][1]=min(f[j][i][k][1],f[j][i-1][k-1][1]+(x[i]-x[i-1]));
				
				f[j][i][k][1]=min(f[j][i][k][1],f[j][i-1][k][0]+(x[i]-x[j]));
				if(f[j][i-1][k-1][0]+x[i]-x[j]<=t[i])
					f[j][i][k][1]=min(f[j][i][k][1],f[j][i-1][k-1][0]+(x[i]-x[j]));
				
				if(f[j][i][k][0]<kInf)
					ans=max(ans,k);
				
				if(f[j][i][k][1]<kInf)
					ans=max(ans,k);
				
			}
		}
	}
	printf("%d",ans);
	return 0;
}
posted @ 2021-12-09 12:00  wzx_believer  阅读(26)  评论(0编辑  收藏  举报