NYOJ304(区间DP)

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=304

一个区间里面有很多不重复的灯,机器人从其中一个灯开始关灯。给出灯和原点的距离 和 灯的功率,问机器人从开始关灯到关灯结束总共浪费的电能机器人每秒移动一米。因为各个灯消耗的电能不一样,所以机器人的关灯的选择有一定策略思路。

 区间dp
dp[i][j][0]   [i,j]之间的灯关闭了,机器人在第i个灯,浪费的最小电能
dp[i][j][1]   [i,j]之间的灯关闭了,机器人在第j个灯,浪费的最小电能

显然想要计算当前区间[i,j]之间的最小电能,可以由 区间[i+1,j]或 区间[i,j-1]推算
对于这两个区间,可以从任意一个区间的左端点或者右端点到达当前区间
dp[i,j][0] =  min(dp[i+1,j][0] + [i+1,j]区间外浪费的电能, dp[i+1,j][1] + [i+1,j]区间外浪费的电能);
dp[i,j][1] =  min(dp[i,j-1][0] + [i,j-1]区间外浪费的电能, dp[i,j-1][1] + [i,j-1]区间外浪费的电能);

另外:由前缀和[0,i],[0,j]求任意区间和[i,j]的时候 [i,j] = [j,0] - [i-1,0]

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
const int maxn = 1000 + 10;
int dp[maxn][maxn][2];// dp[i][j][0]   [i,j]区间 karl机器人在左端点 的最小消耗   dp[i][j][1] 为在右端点 
int d[maxn], sv[maxn];
int main()
{
    int n, k, a, b;
//    freopen("Input.txt", "r", stdin);
//    freopen("O.txt", "w", stdout);
    while(~scanf("%d", &n))
    {
        memset(d, 0, sizeof(d));
        memset(sv, 0, sizeof(sv));
        memset(dp, 0, sizeof(dp));
        scanf("%d", &k);
        int sumv = 0;// 所有路灯每秒总消耗
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d", &d[i], &b);
            sumv += b;
            sv[i] = b + sv[i-1];
        }
        for(int i = k-1; i > 0; i--)// 初始化前半
        {
            dp[i][k][0] = dp[i+1][k][0] + (sumv-sv[k]+sv[i+1-1])*(d[i+1]-d[i]);
            dp[i][k][1] = dp[i][k][0] + (sumv-sv[k]+sv[i-1])*(d[k]-d[i]);
        }
        for(int i = k+1; i <= n; i++)// 初始化后半
        {
            dp[k][i][1] = dp[k][i-1][1] + (sumv-sv[i-1]+sv[k-1])*(d[i]-d[i-1]);
            dp[k][i][0] = dp[k][i][1] + (sumv-sv[i]+sv[k-1])*(d[i]-d[k]);
        }
        for(int i = k-1; i > 0; i--)// 中间到左边
            for(int j = k+1; j <= n; j++)// 中间到右边
        {
            dp[i][j][0] = min(dp[i+1][j][0] + (sumv-sv[j]+sv[i+1-1])*(d[i+1]-d[i]),
                              dp[i+1][j][1] + (sumv-sv[j]+sv[i+1-1])*(d[j]-d[i]));
            dp[i][j][1] = min(dp[i][j-1][0] + (sumv-sv[j-1]+sv[i-1])*(d[j]-d[i]),
                              dp[i][j-1][1] + (sumv-sv[j-1]+sv[i-1])*(d[j]-d[j-1]));
        }
        int ans = min(dp[1][n][0], dp[1][n][1]);
        printf("%d\n", ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值