洛谷 P1220 关路灯 区间dp

题面

https://www.luogu.com.cn/problem/P1220

分析

考虑区间dp

dp[l][r][0]为已经关了[l,r]的灯,当前位置在l的最少功耗;

dp[l][r][1]为已经关了[l,r]的灯,当前位置在r的最少功耗。

可以发现,因为状态是区间的扩大,故只有如下情况:

若当前为dp[l][r][0],上一个状态要么是从l+1点向左走了1格,即dp[l+1][r][0]+cost(l,l+1);或者是从r点向左走了rl+1格,即dp[l+1][r][1]+cost(l,r)

若当前为dp[l][r][1],上一个状态要么是从r1点向右走了1格,即dp[l][r1][1]+cost(r1,r);或者是从l点向右走了rl+1格,即dp[l][r1][0]+cost(l,r)

考虑cost的计算:

可以发现,cost的计算与跑动的时间、目前仍在运行的灯数均有关。当从x跑到y时,且当前[l,r]的灯已被关闭时:

目前仍在运行的灯数(功率)为sum[l1]+(sum[n]sum[r]),跑动时间为(yx)

故cost函数可以写为:

int count(int x, int y, int l, int r) {
    return (pos[y] - pos[x]) * (sum[l - 1] + (sum[n] - sum[r]));
}

Code

#include<iostream>
#include<cstdio>
#include<cstring>

const int maxn = 50 + 10;
const int inf = 0x3f3f3f3f;
int n, c;
int pos[maxn], p[maxn], sum[maxn];
int dp[maxn][maxn][2];

int count(int x, int y, int l, int r) {
    return (pos[y] - pos[x]) * (sum[l - 1] + (sum[n] - sum[r]));
}

int main() {
    memset(dp, inf, sizeof(dp));
    scanf("%d%d", &n, &c);
    for (int i = 1; i <= n; i++) {
        scanf("%d%d", &pos[i], &p[i]);
        sum[i] = sum[i - 1] + p[i];
        //dp[i][i][0]=dp[i][i][1]=0;
    }
    dp[c][c][0] = dp[c][c][1] = 0;
    for (int len = 2; len <= n; len++)
        for (int i = 1; i + len - 1 <= n; i++) {
            int j = i + len - 1;
            dp[i][j][0] = std::min(dp[i + 1][j][0] + count(i, i + 1, i + 1, j),
                                   dp[i + 1][j][1] + count(i, j, i + 1, j));
            dp[i][j][1] = std::min(dp[i][j - 1][1] + count(j - 1, j, i, j - 1),
                                   dp[i][j - 1][0] + count(i, j, i, j - 1));
        }
    int ans = std::min(dp[1][n][0], dp[1][n][1]);
    printf("%d", ans);
    return 0;
}

posted @   SxtoxA  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
12 13
点击右上角即可分享
微信分享提示