洛谷P1220 关路灯

written on 2022-02-06

关于区间dp的话,其实自己还懂得不是特别多

所以第一篇luogu博客就交给 关路灯 这道练习区间dp和dp转移的好题好了


首先审题,对于一道可能作为动态规划的题目来说,我们应该先去关注的是:一个状态是从何而来的

我们发现,这个人来回走动去关路灯,每一个阶段肯定是多关了一个路灯,然而又是在区间内运动并且转移的,那么这就是一道经典而好做的与实际问题结合的区间dp题

首先定义状态\(f[l][r]\)为关掉所有在区间\(l,r\)内的路灯 (注意,其它区间的灯都没有关掉) 所花费的最少功率

但是还要确定人的位置,于是再在最后加一维表示人在l还是在r (因为关完这一区间的路灯后人肯定是在l或r的)\(f[l][r][k],k==0\)\(1\)

消耗的功率,自然就要看其它不在这一区间内的路灯了。这里我们可以用一个前缀和来维护总功率

于是,状态转移就显然了,可以看看代码里的转移方程,再自己理解一下

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int n,st;
ll f[205][205][2];
ll p[205],a[205],s[205];
int main()
{
	scanf("%d%d",&n,&st);
	memset(f,0x7f,sizeof(f));
	for(int i=1;i<=n;i++) scanf("%lld%lld",&p[i],&a[i]),s[i]=s[i-1]+a[i];
	f[st][st][0]=f[st][st][1]=0;
	for(int len=2;len<=n;len++)
	{
		for(int i=1;i<=n-len+1;i++)
		{
			int j=i+len-1;
			f[i][j][0]=min(f[i][j][0],f[i+1][j][0]+(s[i]+s[n]-s[j])*(p[i+1]-p[i]));
			f[i][j][0]=min(f[i][j][0],f[i+1][j][1]+(s[i]+s[n]-s[j])*(p[j]-p[i]));
			f[i][j][1]=min(f[i][j][1],f[i][j-1][1]+(s[i-1]+s[n]-s[j-1])*(p[j]-p[j-1]));
			f[i][j][1]=min(f[i][j][1],f[i][j-1][0]+(s[i-1]+s[n]-s[j-1])*(p[j]-p[i]));
		}
	}
	printf("%lld",min(f[1][n][1],f[1][n][0]));
	return 0;
}
posted @ 2022-07-31 17:10  Freshair_qprt  阅读(43)  评论(0编辑  收藏  举报