2023.04.10 定时测试随笔 T2

发布时间 2023-04-10 16:30:32作者: florence25

T2 关路灯

传送门:洛谷P1220

这是一道区间DP的题

关于关灯是没有时间流逝的,当你经过一个灯的时候它就关了,所以当你最后把整个区间的灯关完且所用的电最少你只有可能在 \(1\) 或者是 \(n\)

当你关完当前一个灯时,你有两种决策可以得到最优解,一个是继续沿着当前的方向继续走下去关一个功率较小的灯, 另一个是折返回去关一个功率较大的灯;

一道能够用动态规划做的题一定包含了两个特点 : 最优子结构重叠子问题
对于这个题区间 [1, n] 的最优解一定是通过 [2, n] 或 [1, n - 1] 的最优解通过折返或者沿原方向得来的,所以我们定义状态:dp[i][j][0/1] 表示区间 [i, j] 中的所有灯已经关完了工人站在 \(i\)\(j\) 位置的最优解;

状态转移方程式:

dp[i][j][0] = min(dp[i + 1][j][0] + (a[i + 1] - a[i]) * (sum[n] - sum[j] + sum[i]), dp[i + 1][j][1] + (a[j] - a[i]) * (sum[n] - sum[j] + sum[i]));

dp[i][j][1] = min(dp[i][j - 1][0] + (a[j] - a[i]) * (sum[n] - sum[j - 1] + sum[i - 1]), dp[i][j - 1][1] + (a[j] - a[j - 1]) * (sum[n] - sum[j - 1] + sum[i - 1]));

因为不知道最后是站在 \(1\) 还是 \(n\) 最优,ans = min(dp[1][n][0], dp[1][n][1]);


贴代码:

#include <bits/stdc++.h>

using namespace std;

const int maxn = 50 + 5;
int n, m;
int f[maxn][maxn][2], sum[maxn], a[maxn], c[maxn];

void read() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++ i) {
		scanf("%d%d", &a[i], &c[i]);
		sum[i] = sum[i - 1] + c[i];
	}
	memset(f, 0x3f, sizeof f);
	f[m][m][0] = f[m][m][1] = 0;
	for (int d = 2; d <= n; ++ d) {
		for (int i = 1, j; (j = i + d - 1) <= n; ++ i) {
			f[i][j][0] = min(f[i + 1][j][0] + (a[i + 1] - a[i]) * (sum[n] - sum[j] + sum[i]), f[i + 1][j][1] + (a[j] - a[i]) * (sum[n] - sum[j] + sum[i]));
			f[i][j][1] = min(f[i][j - 1][0] + (a[j] - a[i]) * (sum[n] - sum[j - 1] + sum[i - 1]), f[i][j - 1][1] + (a[j] - a[j - 1]) * (sum[n] - sum[j - 1] + sum[i - 1]));
		}
	}
	printf("%d\n", min(f[1][n][1], f[1][n][0]));
}

int main() {
	read();
	return 0;
}