链接:https://www.nowcoder.com/acm/contest/93/J
我国现在能源消耗非常严重,现在政府有这样一个工作,每天早上都需要把一些路灯关掉,但是他们想让在关闭的过程中所消耗的能源是最少的,负责路灯关闭的工作人员以1m/s的速度进行行走,假设关闭路灯的时候不需要花费任何的时间,请你编写一个程序,计算在给定路灯位置和每个路灯的消耗能源的多少,求出当所有路灯关闭的时候所需要的最少能量
显然可以得到一个结论,关闭[i, j]区间的电灯以后,关闭i-1或者j+1是下一步的最佳选择,所以可以通过区间dp来解决问题,dp[i][j][0/1]:已经关闭区间[i, j]的电灯,且站在左端点或者右端点的最小能源花费。然后每次关灯的路上的能源花费显然是[1, i-1]和[j+1, n]的电灯在费电。加个前缀和即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 5;
const int INF = 0x3f3f3f3f;
int n, st;
int dist[maxn], w[maxn], pre[maxn];
int dp[maxn][maxn][2];
int dfs(int i, int j, int idx)
{
if(i > j) return 0;
if(dp[i][j][idx] != INF) return dp[i][j][idx];
if(i == j) return INF;
int ret = INF;
if(idx == 0)
{
ret = min(dfs(i+1,j,0) + (pre[n]-pre[j] + pre[i])*(dist[i+1]-dist[i]), dfs(i+1,j,1) + (pre[n]-pre[j] + pre[i])*(dist[j]-dist[i]));
}
else
{
ret = min(dfs(i,j-1,0) + (pre[n]-pre[j-1] + pre[i-1])*(dist[j]-dist[i]), dfs(i,j-1,1) + (pre[n]-pre[j-1] + pre[i-1])*(dist[j]-dist[j-1]));
}
// printf("[%d, %d, %d] = %d\n", i, j, idx, ret);
return dp[i][j][idx] = ret;
}
int main()
{
while(~scanf("%d%d", &n, &st))
{
for(int i = 1; i <= n; i++) scanf("%d%d", &dist[i], &w[i]), pre[i] = pre[i-1] + w[i];
memset(dp, INF, sizeof(dp));
dp[st][st][0] = dp[st][st][1] = 0;
printf("%d\n", min(dfs(1, n, 0), dfs(1, n, 1)));
}
return 0;
}