首页 > 试题广场 >

wyh的问题

[编程题]wyh的问题
  • 热度指数:14 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

我国现在能源消耗非常严重,现在政府有这样一个工作,每天早上都需要把一些路灯关掉,但是他们想让在关闭的过程中所消耗的能源是最少的,负责路灯关闭的工作人员以1m/s的速度进行行走,假设关闭路灯的时候不需要花费任何的时间,请你编写一个程序,计算在给定路灯位置和每个路灯的消耗能源的多少,求出当所有路灯关闭的时候所需要的最少能量


输入描述:
多组测试数据循环输入
每组测试数据第一行:N表示路灯的数量 (2<=N <=1000)
第二行:V表示开始关灯的路灯号码。 (1<=V<=N)
接下来的N行中,每行包含两个用空格隔开的整数D和W,用来描述每盏灯的参数
D表示该路灯到原点的距离 (用米为单位来表示),
W表示灯泡的功率,即每秒该灯泡所消耗的能量数。(0<=D<=1000,0<=W<=1000)
路灯按照顺序给出,起始位置的那盏灯不算消耗的电能里面


输出描述:
输出一个整数,即消耗能量之和的最小值。
示例1

输入

4
3
2 2
5 8
6 1
8 7

输出

56

说明

对于样例,我一开始在第三个路灯的位置,即在6位置
第1s的时候去5把第二盏灯关闭,消耗电能8
然后去第四盏灯,第四盏灯亮的时间是4s 所以消耗电能28
最后去关第一盏灯第一盏灯亮的时间是10s 所以消耗电能20
最后总和为8+28+20=56
这道题的判题后台出了问题,实际上代码是可以AC的。递归很容易想,转为dp的时候被绕晕了,有一个通过无效动作来转移状态的方法没想到。边界抠了几个小时才搞定。
import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        while (sc.hasNext()){
            int N=sc.nextInt();
            int V=sc.nextInt();
            int D[]=new int[N+1];
            int W[]=new int[N+1];
            for(int i=1;i<=N;i++){
                D[i]=sc.nextInt();
                W[i]=sc.nextInt();
                W[i]+=W[i-1];
            }
            //定义dp[i][j][2],看成二维dp表,一个单元格存两个数,就好理解。
            //将数组分为三部分,最中间的是处理过的,那么肯定右两个指针分割它们,那么,dp[i][j]的意义为
            //已经处理过的部分[i,j],消耗的最小能源值是多少
            //每次去往下一个地方,就是i和j向左右扩展,并且工作人员当前要嘛在i处,要吗在j处
            //每次去往下一个地方花的时间算出来,乘以[1,i-1]以及[i+1,N]上的功率总和。就是浪费的时间
            //W[i]就是用来加速求一个段上的总和的,比如总和[1,i]就是W[i],总和[i+1,N],就是W[N]-W[i]
            //dp[][][0]的意思是,当前位置在左边的状态,同理dp[][][1]表示当前位置在右边的状态
            //显然,最开始的时候当前位置即可以看作在左边,也可以看作在右边,那么的dp[V][V][0]=dp[V][V][1]=0
            //最终结束的位置是dp[1][N]
            long dp[][][]=new long[N+1][N+1][2];
            //画表后得知,三个条件,i<=V,j>=V,且i<j,可知只需对右上角的小正方形做dp即可(其左底角位置为[V][V])
            //状态依赖为dp[i][j]依赖dp[i+1][j]和dp[i][j-1]。具体看dp主体。可知每个单元格依赖它下面的和左边的,即从下到上,从左往右dp即可。
            //那么,需要填写base case,即第V行的前V个,和第V列的前V个

            //第V列 从下往上时,dp只依赖于它下面的,根据意义可知,它下面的单元格j是固定为V的,回归到题意,说明一次也不能往右移动,每次都只能往左移动
            //所以dp[i][V][0]是如何求的,很容易理解
            //而dp[i][V][1]怎么求呢,很简单,dp[i][V][0]变为dp[i][V][1],意思就是从这头跑到那头,不关任何灯
            for(int i=V-1;i>0;i--){
                dp[i][V][0]=dp[i+1][V][0]+(D[i+1]-D[i])*(W[i]+W[N]-W[V]);
                dp[i][V][1]=dp[i][V][0]+(D[V]-D[i])*(W[i-1]+W[N]-W[V]);
            }
            //同理求dp[V][i]..
            for(int i=V+1;i<=N;i++){
                dp[V][i][1]=dp[V][i-1][1]+(D[i]-D[i-1])*(W[V-1]+W[N]-W[i-1]);
                dp[V][i][0]=dp[V][i][1]+(D[i]-D[V])*(W[V-1]+W[N]-W[i]);
            }
            //写不写都行,dp[V][V][0]=dp[V][V][1]=0;
            for(int i=V-1;i>0;i--){
                for(int j=V+1;j<=N;j++){
                    dp[i][j][0]=Math.min(dp[i+1][j][1]+(D[j]-D[i])*(W[i]+W[N]-W[j]),dp[i+1][j][0]+(D[i+1]-D[i])*(W[i]+W[N]-W[j]));
                    dp[i][j][1]=Math.min(dp[i][j-1][0]+(D[j]-D[i])*(W[i-1]+W[N]-W[j-1]),dp[i][j-1][1]+(D[j]-D[j-1])*(W[i-1]+W[N]-W[j-1]));
                }
            }
            System.out.println(Math.min(dp[1][N][0],dp[1][N][1]));
        }
    }

}

发表于 2019-06-12 23:18:49 回复(0)