CODEVS 1258 關路燈

寫動歸終於能不看題解一次A了!(其實交了兩次,一次80一次A)

我練功發自真心!


題目描述 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


區間動規,然而我並沒有用到區間長度?

每次的行動都是擴展已經關掉的區間,直至關掉燈的區間覆蓋整個1-n路燈區間

在區間內,人要麼停在左端點,要麼停在右端點,而停在區間中間是浪費時間的行爲

兩種狀態分開處理

f1(人在左邊)[左區間][右區間]=最小耗電量

f2(人在右邊)[左區間][右區間]=最小耗電量

當人在一個區間的右端點,要向右擴展一單位區間時,代價是dis[右端點][右端點+1]*未關的燈的功耗,向左同理


//動規 
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int f1[1100][1100];//人在區間左
int f2[1100][1100];//人在區間右 
int s[1100];
int dis[1100];
int w[1100];
int n;
int dp(int v){
	int i,j;
	int len=1;
	for(i=v;i>=1;i--)
	  for(j=v;j<=n;j++){
	  	len=dis[j]-dis[i];
	  	f2[i][j]=min(f2[i][j],f1[i][j]+len*(s[n]-s[j]+s[i-1]));
	  	f1[i][j]=min(f1[i][j],f2[i][j]+len*(s[n]-s[j]+s[i-1]));
	  	int k;
	  	for(k=j+1;k<=n;k++){
	  		f2[i][k]=min(f2[i][k],f2[i][k-1]+(dis[k]-dis[k-1])*((s[n]-s[k-1])+s[i-1]));
		  }
		for(k=i-1;k>=1;k--){
			f1[k][j]=min(f1[k][j],f1[k+1][j]+(dis[k+1]-dis[k])*((s[n]-s[j])+s[k]));
		  }
	  }
	return 1;
}
int main(){
	int v;
	scanf("%d\n%d",&n,&v);
	int i,j;
	for(i=1;i<=n;i++){
		scanf("%d%d",&dis[i],&w[i]);
		s[i]=s[i-1]+w[i];//總功率 
	}
	memset(f1,1111,sizeof(f1));//初始化 
	memset(f2,1111,sizeof(f2));
	for(int i=1;i<=n;i++)f1[i][i]=0,f2[i][i]=0;
	dp(v);//以v爲起始點開始動規 
	int ans=min(f1[1][n],f2[1][n]);
	printf("%d",ans);
	//print
	return 0;
}


“爲什麼不肯花錢裝個總閘”


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章