洛谷P1220 关路灯题解

这道题是一道区间dp的题目

我们如何看出他是区间dp?

因为他是在一条线上从小区间不断向大区间扩散,长度不断增加,所以大区间的答案一定是从小区间的答案更新而来

题目已知的信息有区间位置,和功率和米数,所以我们要从这些信息入手。

如何设计dp状态?

我们观察到我们需要保存小区间的答案,所以我们前两维可以定位i-j区间都被关闭的最小功率,但是这样显然还是不够的,我们还要一种状态叫做向左向右。

所以我们可以设计第三维为在左端点和右端点,根据他来更新之后向左和向右的答案。

消耗可以用作功率*米数,我们还需要保存sum数组,用来保存任意区间内在1s内消耗的功率,这样就能更新所有状态

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=110;
struct node{
    int p;
    int x;
}s[N];
int f[N][N][2];
int sum[N][N];
int main(){
    int n;
    int c;
    cin>>n>>c;
    int i;
    for(i=1;i<=n;i++){
        cin>>s[i].x>>s[i].p;
    }
    int j;
    for(i=1;i<=n;i++){
        sum[i][i]=s[i].p;
        for(j=i+1;j<=n;j++){
            sum[i][j]=sum[i][j-1]+s[j].p;
        }
    }
    memset(f,0x3f,sizeof f);
    f[c][c][0]=f[c][c][1]=0;
    int len;
    int l,r;
    for(len=2;len<=n;len++){
        for(l=1;l+len-1<=n;l++){
            r=l+len-1;
            f[l][r][0]=min(f[l+1][r][0]+(s[l+1].x-s[l].x)*(sum[1][l]+sum[r+1][n]),f[l+1][r][1]+(s[r].x-s[l].x)*(sum[1][l]+sum[r+1][n]));
            f[l][r][1]=min(f[l][r-1][1]+(s[r].x-s[r-1].x)*(sum[1][l-1]+sum[r][n]),f[l][r-1][0]+(s[r].x-s[l].x)*(sum[1][l-1]+sum[r][n]));
        }
    }
     cout<<min(f[1][n][0],f[1][n][1])<<endl;    
}
View Code

 

posted @ 2020-01-30 10:39  朝暮不思  阅读(153)  评论(0编辑  收藏  举报