洛谷p1220 dp

题目链接: 洛谷p1220

这道题是个dp的题目,首先我们就要考虑,老张去关路灯,存不存在一种情况就是我人在3的位置,我去走到5关灯,在走到4去关4的灯。这是不可能存在的是不是,也就是说关灯只会是从已经关好灯的区间去延伸一个单位,假设我们目前在3 的位置,那么我们接下来关的下一盏灯就是2或者是4.换一种表达就是,当前已经关好灯的区间是[3,3],那么我们下一步关完灯后就只可能是[2,3]或者是[3,4],就是所在区间的左端点去-1,或者右端点去+1;如果我们设计状态是 f[i][j] 表示关完[i,j]这个区间的灯所花费的最少价值的话,那么从起点处去转移状态,答案应该就是f[1][n];
怎么转呢?
就是当前我是在[i,j]这个区间内,然后所在位置是node;
那么

int t = abs(street_light[L - 1].node - node);
f[L - 1][R] = min(f[L - 1][R], f[L][R] + t * sum[L - 1] + t * (sum[n] - sum[R]));

t就是从node这个位置走到L-1这个灯位置的时间,然后sum数组是一个所有路灯功率的前缀和,其实我们就是要算现在剩下还亮着的路灯经过这t秒后消耗了多少功率。
这是L-1,R+1的转移的基本一样的。

f[L][R + 1] = min(f[L][R + 1], f[L][R]  + t * sum[L - 1] + t * (sum[n] - sum[R]));

如果这么去做,结果只有90分,wa最后一个点~~(数据太水了)~~ 。为什么只有90?因为我们这么去转移是会有一个问题,我们仅仅是表示了[i,j]区间的答案,但是我ij区间去往下一个区间转移的时候,有两种可能,一种是我在ij区间的i位置,一种是在ij区间的j位置。然后这两种位置对于下一个区间的贡献是不一样的,我们没有去分别讨论这两种情况。所以就是在加一维度,去表示我现在在ij区间的左边还是右边,在去进行转移即可。

void dp(int L,int R,int node,int value, int pan) {
	if (L == 1 && R == n) return;
	if (L - 1 >= 1) {
		//从当前node的位置走到street_light[L-1]的路灯的位置
		int t =  node - street_light[L - 1].node;
		if (f[L - 1][R][0] > f[L][R][pan] + t * sum[L - 1] + t * (sum[n] - sum[R])) {
			f[L - 1][R][0] = min(f[L - 1][R][0], f[L][R][pan] + t * sum[L - 1] + t * (sum[n] - sum[R]));
		    dp(L - 1, R, street_light[L - 1].node, f[L - 1][R][0], 0);
		}	
	}
	if (R + 1 <= n) {
		//从当前node的位置走到street_light[R+1]的路灯的位置
		int t = street_light[R + 1].node - node;
		if (f[L][R + 1][1] > f[L][R][pan] + t * sum[L - 1] + t * (sum[n] - sum[R])) {
			f[L][R + 1][1] = min(f[L][R + 1][1], f[L][R][pan] + t * sum[L - 1] + t * (sum[n] - sum[R]));
		    dp(L, R + 1, street_light[R + 1].node, f[L][R + 1][1], 1);
		}		
	}
}

我选择是去递归的形式去填,然后pan这个参量就是表示我现在在L,R区间的左边还是右边(0表示左边,1表示右边);
我们从[L,R]往[L-1,R]去延伸,很明显延伸完我们是在左边,所以得到的是f[L-1][R][0];R+1的转移同理。其实加了一维对于上面二维仅仅只是在去表示了你在这个区间是在左端点还是右端点而已。
最后答案就是min(f[1][n][1],f[1][n][0]);


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstring>
#include<stack>
#define ll long long
using namespace std;
const long long max_ = 1e9 + 7;
inline ll read() {
	ll s = 0, f = 1;
	char ch = getchar();
	while (ch<'0' || ch>'9') {
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0'&&ch <= '9') {
		s = s * 10 + ch - '0';
		ch = getchar();
	}
	return s * f;
}
int n,sum[100], first,f[100][100][2];
//                    0表示在左边,1 表示在右边
struct k {
	int p, node;
}street_light[100];
void dp(int L,int R,int node,int value, int pan) {
	if (L == 1 && R == n) return;
	if (L - 1 >= 1) {
		//从当前node的位置走到street_light[L-1]的路灯的位置
		int t =  node - street_light[L - 1].node;
		if (f[L - 1][R][0] > f[L][R][pan] + t * sum[L - 1] + t * (sum[n] - sum[R])) {
			f[L - 1][R][0] = min(f[L - 1][R][0], f[L][R][pan] + t * sum[L - 1] + t * (sum[n] - sum[R]));
		    dp(L - 1, R, street_light[L - 1].node, f[L - 1][R][0], 0);
		}	
	}
	if (R + 1 <= n) {
		//从当前node的位置走到street_light[R+1]的路灯的位置
		int t = street_light[R + 1].node - node;
		if (f[L][R + 1][1] > f[L][R][pan] + t * sum[L - 1] + t * (sum[n] - sum[R])) {
			f[L][R + 1][1] = min(f[L][R + 1][1], f[L][R][pan] + t * sum[L - 1] + t * (sum[n] - sum[R]));
		    dp(L, R + 1, street_light[R + 1].node, f[L][R + 1][1], 1);
		}		
	}
}
int main() {
	cin >> n >> first;
	for (int i = 0; i <= 70; i++) {
		for (int j = 0; j <= 70; j++) {
			f[i][j][1] = 100000;
		f[i][j][0] = 1000000;
		}
	}
	for (int i = 1; i <= n; i++) {
		cin>>street_light[i].node;
		cin>>street_light[i].p;
		sum[i] = sum[i - 1] + street_light[i].p;
	}
	f[first][first][1] = 0; f[first][first][0] = 0;
	dp(first, first, street_light[first].node,0,1);
	cout << min(f[1][n][1] , f[1][n][0]);
	return 0;
}
发布了32 篇原创文章 · 获赞 3 · 访问量 665

猜你喜欢

转载自blog.csdn.net/qq_43804974/article/details/102166899