洛谷 P1220 关路灯

题目传送门

\(dp\)真的一蹶不振了,不过不得不说题解的思路真的妙。。。

感觉现在\(dp\)卡在了状态设计上,只要设计出状态,转移方程和初始化其实都是小问题。

思路

其实没有任何思路,首先你要看出来这是一个区间\(dp\),然后你要设计出状态:\(f_{i,j,0/1}\)表示在区间\([i,j]\)上站在左端点还是右端点。然后这个题就做完了。。。

\([l,r]\)这个区间只能由\([l+1,r]\)或者\([l,r-1]\)转移而来,所以转移方程非常简单,直接看代码即可。所以设计状态才是最重要的啊。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
int n,c;
int w[110],p[110],sum[110];
int f[110][110][5];
int main()
{
	scanf("%d%d",&n,&c);
	memset(f,0x3f,sizeof(f));
	for(int i=1;i<=n;i++){
		scanf("%d%d",&p[i],&w[i]);
		sum[i]=sum[i-1]+w[i];
	}
	f[c][c][0]=0;
	f[c][c][1]=0;//初始化
	for(int len=2;len<=n;len++){
		for(int l=1,r=l+len-1;r<=n;l++,r++){
			f[l][r][0]=min(f[l+1][r][0]+(p[l+1]-p[l])*(sum[n]-sum[r]+sum[l]),f[l+1][r][1]+(p[r]-p[l])*(sum[n]-sum[r]+sum[l]));
			f[l][r][1]=min(f[l][r-1][1]+(p[r]-p[r-1])*(sum[n]-sum[r-1]+sum[l-1]),f[l][r-1][0]+(p[r]-p[l])*(sum[n]-sum[r-1]+sum[l-1]));//简单易懂的转移方程
		}
	}
	printf("%d\n",min(f[1][n][0],f[1][n][1]));
	return 0;
} 

不敢相信这是道蓝题。。。

posted @ 2020-12-03 21:00  徐明拯  阅读(39)  评论(0编辑  收藏  举报