这题目想了很有一段时间,最后发现关一个区间的路灯最后的位置要么在最左端要么在最右端,只有两种状态所以建立状态,[i,j]表示这个区间的路灯最小消耗,0代表在最左端,1代表在最右端。这题目还有个坑点不能用while(scanf("%d%d",&n,&s)==2)一直90分最后看别人的把while去了就过了。。。汗颜。。。
状态方程式dp[j][i][0]=min(dp[j+1][i][0]+(x[j+1]-x[j])*(sum[n]-(sum[i]-sum[j])),dp[j+1][i][1]+(x[i]-x[j])*(sum[n]-(sum[i]-sum[j])))
和dp[j][i][1]=min(dp[j][i-1][0]+(x[i]-x[j])*(sum[n]-(sum[i-1]-sum[j-1])),dp[j][i-1][1]+(x[i]-x[i-1])*(sum[n]-(sum[i-1]-sum[j-1])))
sum表示灯泡功率的前缀和每一个区间[j,i]只会由[j+1,i]和[j,i-1]推出,所以状态方程如上。
代码如下:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
const int maxn=1000;
const int inf=99999999;
int n,s;
int dp[maxn][maxn][2]={},x[maxn]={},w[maxn]={},sum[maxn]={};
inline int cime(int x,int y,int x1,int y1){
return abs(dp[x][y][2]-dp[x1][y1][1]);
}
int main()
{
scanf("%d%d",&n,&s);
memset(dp,999,sizeof(dp));
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++){
scanf("%d%d",&x[i],&w[i]);
sum[i]=sum[i-1]+w[i];
}
dp[s][s][0]=dp[s][s][1]=0;
for(int i=s;i<=n;i++)
for(int j=i-1;j>=1;j--){
dp[j][i][0]=min(dp[j+1][i][0]+(x[j+1]-x[j])*(sum[n]-(sum[i]-sum[j])),dp[j+1][i][1]+(x[i]-x[j])*(sum[n]-(sum[i]-sum[j])));
dp[j][i][1]=min(dp[j][i-1][0]+(x[i]-x[j])*(sum[n]-(sum[i-1]-sum[j-1])),dp[j][i-1][1]+(x[i]-x[i-1])*(sum[n]-(sum[i-1]-sum[j-1])));
}
printf("%d\n",min(dp[1][n][1],dp[1][n][0]));
return 0;
}