(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
",min(f[1][n][0],f[1][n][1]));
return 0;
}
不敢相信这是道蓝题。。。