洛谷 [P1220] 关路灯

本题是一道区间DP,很容易设计出状态, dp[i][j]代表关掉i到j的路灯所耗的电量,但是对于新到一个路灯来说,可以是原来直接来的,也可以是掉头来的,于是还需要添加一维 0代表在区间的左端,1代表在区间的右端。从最开始所在的地方扩展。
因为涉及连续区间,可以采用前缀和优化。

有如下转移方程:
dp[i][j][1]=min(dp[i][j-1][1]+pre[i][j-1](dis[j]-dis[j-1]),dp[i][j-1][0]+pre[i][j-1](dis[j]-dis[i]));
dp[i][j][0]=min(dp[i+1][j][0]+pre[i+1][j](dis[i+1]-dis[i]),dp[i+1][j][1]+pre[i+1][j](dis[j]-dis[i]));

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;
const int MAXN=105;
int init(){
	int rv=0,fh=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') fh=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		rv=(rv<<1)+(rv<<3)+c-'0';
		c=getchar();
	}
	return fh*rv;
}
int dp[MAXN][MAXN][2],dis[MAXN],P[MAXN],n,loc,pre[MAXN][MAXN];
int main(){
	freopen("in.txt","r",stdin);
	n=init();loc=init();
	for(int i=1;i<=n;i++){
		dis[i]=init();
		P[i]=init();
	}
	for(int i=n;i>=1;i--){
		dis[i]=dis[i]-dis[1];
	}
	pre[1][n]=0;
	for(int i=1;i<=n-1;i++){
		pre[i][n]=pre[i-1][n]+P[i-1];
		for(int j=n-1;j>=i;j--){
			pre[i][j]=pre[i][j+1]+P[j+1];
		}
	}
	memset(dp,0x3f,sizeof(dp));
	dp[loc][loc][0]=dp[loc][loc][1]=0;
	for(int i=loc;i>=1;i--){
		for(int j=i+1;j<=n;j++){
			dp[i][j][1]=min(dp[i][j-1][1]+pre[i][j-1]*(dis[j]-dis[j-1]),dp[i][j-1][0]+pre[i][j-1]*(dis[j]-dis[i]));
			dp[i][j][0]=min(dp[i+1][j][0]+pre[i+1][j]*(dis[i+1]-dis[i]),dp[i+1][j][1]+pre[i+1][j]*(dis[j]-dis[i]));
		}
	}
	cout<<min(dp[1][n][0],dp[1][n][1]);
	fclose(stdin);
	return 0;
}

原文地址:https://www.cnblogs.com/Mr-WolframsMgcBox/p/7905872.html