HLOJ434 关灯

版权声明:蒟蒻的原创,转载请注明出处,附上链接。 https://blog.csdn.net/qq_39670434/article/details/79979493

题目

题目描述
宁智贤得到了一份有趣而高薪的工作。每天早晨她必须关掉她所在村庄的街灯。所有的街灯都被设置在一条直路的同一侧。 宁智贤每晚到早晨5点钟都在晚会上,然后她开始关灯。开始时,她站在某一盏路灯的旁边。 每盏灯都有一个给定功率的电灯泡,因为宁智贤有着自觉的节能意识,她希望在耗能总数最少的情况下将所有的灯关掉。 宁智贤因为太累了,所以只能以1m/s的速度行走。关灯不需要花费额外的时间,因为当她通过时就能将灯关掉。 编写程序,计算在给定路灯设置,灯泡功率以及宁智贤的起始位置的情况下关掉所有的灯需耗费的最小能量。
输入格式
第一行包含一个整数N,2≤N≤1000,表示该村庄路灯的数量。
第二行包含一个整数V,1≤V≤N,表示宁智贤开始关灯的路灯号码。
接下来的N行中,每行包含两个用空格隔开的整数D和W,用来描述每盏灯的参数,其中0≤D≤1000,0≤W≤1000。
D表示该路灯与村庄开始处的距离(用米为单位来表示),W表示灯泡的功率,即在每秒种该灯泡所消耗的能量数。路灯是按顺序给定的。
输出格式
第一行即唯一的一行应包含一个整数,即消耗能量之和的最小值。

题解

说实话,这道区间DP拿到手想了四十分钟一点思路都没有……看的题解才写出来的。。
这道题目要做的第一步是把所有的灯按照坐标进行排序
然后设出状态f[i][j]代表把第i盏灯到第j栈灯全部关闭的最小消耗。
但是问题出现了,我们发现对于一个区间[i,j],我们从i走到j的消耗和从j走到i的消耗是不一样的,所以我们新开一维,f[i][j][1]代表从左走到右边,f[i][j][0]代表从右走到左边。
对于f[i][j],我们只能从左边或者右边递推而来,也就是从f[i][j1]或者f[i+1][j]推来。

code

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int num = 0;
    char c = ' ';
    bool flag = true;
    for(;c > '9' || c < '0';c = getchar())
    if(c == '-')
    flag = false;
    for(;c >= '0' && c <= '9';num = num*10+c-48,c=getchar());
    return flag ? num : -num;
}
const int maxn=1020;
int n,begining,P[maxn],sum[maxn][maxn];
//P是a[].power的前缀和
//sum[i][j]代表除去[i,j]的灯后的功率和 
struct light
{
    int direct,power;
}a[maxn];
bool mycmp(light a,light b)
{
    return a.direct<b.direct;
};
void init()
{
    n=read();
    begining=read();
    for(int i=1;i<=n;i++)
    {
        a[i].direct=read();
        a[i].power=read();
    }
    sort(a+1,a+1+n,mycmp);//排序 
    for(int i=1;i<=n;i++)
        P[i]=P[i-1]+a[i].power;//前缀和 
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++)
            sum[i][j]=P[n]+P[i-1]-P[j];
}
int f[maxn][maxn][2];
void DP()
{
    memset(f,10,sizeof f);
    f[begining][begining][1]=f[begining][begining][0]=0;
    for(int len=2;len<=n;len++)
        for(int i=1;i+len-1<=n;i++)
        {
            int j=i+len-1;
            int t1,t2;
            t1=f[i+1][j][0]+(a[i+1].direct-a[i].direct)*sum[i+1][j];
            t2=f[i+1][j][1]+(a[j].direct-a[i].direct)*sum[i+1][j];
            f[i][j][0]=min(t1,t2);
            t1=f[i][j-1][0]+(a[j].direct-a[i].direct)*sum[i][j-1];
            t2=f[i][j-1][1]+(a[j].direct-a[j-1].direct)*sum[i][j-1];
            f[i][j][1]=min(t1,t2);
            //这部分画个图就能理解了 
        }
    printf("%d\n",min(f[1][n][0],f[1][n][1]));
}
int main()
{
    init();
    DP();
    return 0;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页