CODEVS 1258 关路灯

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

56


【题目分析】

     首先这个人(多端卡?多瑞卡!)经过的路径一定是一个区间,(因为关路灯不需要时间,顺手关掉就好了,没必要跳过去的),那么他当前的状态就只有两种,那么就是在这个区间的左端点或者是右端点。需要转移到的状态也只有两种:区间左端拓展一个节点或者是区间右端拓展一个节点,那么状态转移方程就很容易写出来了,(当前的状态是在左端点还是右端点,只需要判断一下j和起始位置的大小【自行理解】)。

    注:如果实在左端点,那么转移到dp[i+1][j-1] 和 dp[i+1][j+i] 右端点正好与之相反。(所以需要判断是在左端还是在右端)

    (状态转移方程我写的比较复杂,放在代码里了)

【代码】

#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define M(a) memset(a,0,sizeof a)
const long long inf=10000000000;
int elec[1001][1001];
int dis[1001][1001];
long long dp[1001][1001]; //关的灯的数量,现在的位置; 
int d[1001],w[1001];
int n,st;
long long min(long long a,long long b)
{return a>b?b:a;}
int main()
{
	scanf("%d%d",&n,&st);
	F(i,1,n) scanf("%d%d",&d[i],&w[i]),elec[i][i]=w[i],dis[i][i]=0;
	F(i,1,n-1) F(j,i+1,n) elec[i][j]=elec[i][j-1]+w[j];
	F(i,1,n-1) F(j,i+1,n) dis[i][j]=dis[i][j-1]+d[j]-d[j-1];
    F(i,1,n)F(j,1,n) dp[i][j]=inf;
    dp[1][st]=0;
	for (int i=1;i<n;++i){
		for (int j=1;j<=n;++j){
			if (dp[i][j]<inf)
			{
			  if (j>=st){
			  	dp[i+1][j+1]=min(dp[i+1][j+1],dp[i][j]+(elec[1][j-i]+elec[j+1][n])*dis[j][j+1]);
			  	dp[i+1][j-i]=min(dp[i+1][j-i],dp[i][j]+(elec[1][j-i]+elec[j+1][n])*dis[j-i][j]);
			  }
			  if (j<st){
			  	dp[i+1][j-1]=min(dp[i+1][j-1],dp[i][j]+(elec[1][j-1]+elec[j+i][n])*dis[j-1][j]);
			  	dp[i+1][j+i]=min(dp[i+1][j+i],dp[i][j]+(elec[1][j-1]+elec[j+i][n])*dis[j][j+i]);
			  }
			}
		}
	}
	printf("%lld",dp[n][1]>dp[n][n]?dp[n][n]:dp[n][1]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值