P1220 关路灯

原题链接

导入

1.假如你是老头,你每次关灯最多有两个选择: 一.关最左边的灯 二.关最右边的灯
而你的目的是:使总耗电量最小

Q:那我能不能每次选去关功率大的那个灯呢?
A:不行,因为耗电量还与时间有关

Q:那我能不能每次选去关 路程(时间)功率 较大的灯(即贪心)呢?
A:不行,假设这样一个场景:假设初始在第三个位置(总共8个位置),你的左边有一个功率非常小的灯A=1,左边的左边有一个功率非常大的灯B=1000000,而右边功率都大于A(两位数),如果贪心的话,就会一直选右边,导致B的耗电量巨大。这时候只要不贪心,先把B关掉,这样总耗电量就小了

深入

克服贪心,把当前看起来不划算的选项也算上,这就叫dp(也可以记忆化搜索穷举)。
该如何设计呢?
对于任意一段给定的序列,最后关掉的灯不是左边就是右边。
所以设dp[i][j][op](op{0,1})为关掉 i~j 内所有灯时的当前的所有灯的总耗电量,而非i~j的总耗电量,其中op=0时代表最后关掉的灯在最左端,1代表最右端。对于任一状态而言都是由前两种状态变化而来,而最终答案是两种状态中较小的那个。
又因为必须要从特定点出发,因此某些状态是无法求得的,设无法求得的状态为无穷大,这样如果当前状态的两个前置状态都是无穷大,代表这个状态无法到达,也是无穷大,即只要有能到达的状态就不是无穷大。

代码

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f
struct
{
    int pos;
    int power;
}d[55];
int cons[55][55][2]={0};
int sum[55]={0};
int main()
{
    int n,c;
    scanf("%d%d",&n,&c);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&d[i].pos,&d[i].power);
        sum[i]=sum[i-1]+d[i].power;
    }
    memset(cons,inf,sizeof cons);
    cons[c][c][0]=cons[c][c][1]=0;
    for(int k=2;k<=n;k++)
    {
        for(int i=1;i+k-1<=n;i++)
        {
            int l=i,r=i+k-1;
            cons[l][r][0]=min(cons[l+1][r][0]+(sum[n]-(sum[r]-sum[l]))*(d[l+1].pos-d[l].pos),cons[l+1][r][1]+(sum[n]-(sum[r]-sum[l]))*(d[r].pos-d[l].pos));
            cons[l][r][1]=min(cons[l][r-1][0]+(sum[n]-(sum[r-1]-sum[l-1]))*(d[r].pos-d[l].pos),cons[l][r-1][1]+(sum[n]-(sum[r-1]-sum[l-1]))*(d[r].pos-d[r-1].pos));
        }
    }
    printf("%d\n",min(cons[1][n][0],cons[1][n][1]));
    return 0;
}
posted @   纯粹的  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示