luogu P1220 关路灯
题目链接:luogu P1220 关路灯
题目大意:
题解:
一道区间DP题。
\(dp[i][j]\)表示第\(i\)盏路灯到第\(j\)盏路灯都关掉后,剩下路灯都开着的情况下消耗的最小电能。
由于可以掉头走或者继续走下去,所以增加一维,\(dp[i][j][0]\)表示关完这一段的路灯后留在第\(i\)盏路灯,\(dp[i][j][1]\)表示关完这一段的路灯后留在第\(j\)盏路灯。
状态转移方程:
\[dp[i][j][0]=min(dp[i+1][j][0]+(dis[i+1]-dis[i])*(sum[i]+sum[n]-sum[j]),dp[i+1][j][1]+(dis[j]-dis[i])*(sum[i]+sum[n]-sum[j]))
\]
\[dp[i][j][1]=min(dp[i][j-1][0]+(dis[j]-dis[i])*(sum[i-1]+sum[n]-sum[j-1]),dp[i][j-1][1]+(dis[j]-dis[j-1])*(sum[i-1]+sum[n]-sum[j-1]))
\]
由于不知道关完所有路灯之后是留在哪一端,所以答案为\(dp[1][n][0],dp[1][n][1]\)中较小者。
#include <iostream>
#include <cstring>
using namespace std;
#define io_speed_up ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
int dis[55], p[55], sum[55], n, c, dp[55][55][2];
int main() {
io_speed_up;
cin >> n >> c;
memset(dp, 0x3f, sizeof(dp));
for (int i = 1; i <= n; ++i) {
cin >> dis[i] >> p[i];
sum[i] = sum[i - 1] + p[i];
}
dp[c][c][0] = dp[c][c][1] = 0;
for (int l = 2; l <= n; ++l) {
for (int i = 1; i + l - 1 <= n; ++i) {
int j = i + l - 1;
dp[i][j][0] = min(dp[i + 1][j][0] + (dis[i + 1] - dis[i]) * (sum[i] + sum[n] - sum[j]), \
dp[i + 1][j][1] + (dis[j] - dis[i]) * (sum[i] + sum[n] - sum[j]));
dp[i][j][1] = min(dp[i][j - 1][0] + (dis[j] - dis[i]) * (sum[i - 1] + sum[n] - sum[j - 1]), \
dp[i][j - 1][1] + (dis[j] - dis[j - 1]) * (sum[i - 1] + sum[n] - sum[j - 1]));
}
}
cout << min(dp[1][n][0], dp[1][n][1]);
return 0;
}