洛谷 [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 
#include 
#include 
#include 
#include 
#include 
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<1][n][0],dp[1][n][1]);
    fclose(stdin);
    return 0;
}

你可能感兴趣的:(noip,题解,dp)