题目详情
题目分析:
- dp[i][j][0]表示从编号i到j的灯关闭且老张关完最后一个灯在i位置,即区间左边时最小功耗。
- dp[i][j][1]表示从编号i到j的灯关闭且老张关完最后一个灯在j位置,即区间右边时最小功耗。
- power[i]是从第一个灯到第i个灯的总功耗(前缀和)。
- 因为dp[i][j]必须从dp[i + 1][j]转移过来,所以当转移i + 1时i必须已经转移好了,所以i需要倒序遍历。
- 关的灯一定是连续的,因为顺手关灯一定比路过不关功耗低。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int power[55], location[55], n, c, dp[55][55][2];
int calculate(int bigpos, int smallpos, int left, int right){
return (location[bigpos] - location[smallpos]) * (power[left -1] + power[n] - power[right]);
}
int main()
{
scanf("%d%d", &n, &c);
memset(dp, 0x3f3f3f3f, sizeof(dp));//初始化
for (int i = 1; i <= n; i++)
{
scanf("%d%d", &location[i], &power[i]);
power[i] += power[i - 1];
}
dp[c][c][0] = dp[c][c][1] = 0;
for (int j = c; j <= n; j++)
for (int i = j - 1; i >= 1; i--){
dp[i][j][0] = min(dp[i + 1][j][0] + calculate(i + 1, i, i + 1, j), dp[i + 1][j][1] + calculate(j, i, i + 1, j));
dp[i][j][1] = min(dp[i][j - 1][0] + calculate(j, i, i, j - 1), dp[i][j - 1][1] + calculate(j, j - 1, i, j - 1));
}
printf("%d", min(dp[1][n][0], dp[1][n][1]));
}