做了不少dp,这个题一眼就看出是区间dp来了,不过推了一段时间发现不知道怎么推出状态,最后还是看了题解。这个题是从一个区间的左右两边向这个区间来推。
详细解释看代码吧
// let me get FY
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn = 110;
int a[maxn]; //存位置
int b[maxn]; // 存功率
int sum[maxn]; // 存前几个灯的总功率
int dp[maxn][maxn][2]; // dp区间和两个状态,一个是关完这个区间灯人在左边,另一个是关完这
//个区间灯人在右边
int main()
{
int n, m;
scanf("%d%d", &n, &m);
memset(dp, 0x3f, sizeof(dp));
for(int i = 1; i <= n; i++)
{
scanf("%d%d",&a[i], &b[i]);
sum[i] = sum[i - 1] + b[i];
// printf("%d\n", sum[i]);
}
dp[m][m][0] = dp[m][m][1] = 0;
for(int l = 2; l <= n; l++) // 区间长度
{
for(int i = 1; i <= n - l + 1; i++)
{
int j = l + i - 1;
// printf("%d\n", sum[i] + sum[n] - sum[j]);
dp[i][j][0] = min(dp[i + 1][j][0] + (a[i + 1] - a[i])* (sum[i] + (sum[n] - sum[j])), dp[i + 1][j][1] + (a[j] - a[i]) * (sum[i] + (sum[n] - sum[j])));
dp[i][j][1] = min(dp[i][j - 1][0] + (a[j] - a[i]) * (sum[i - 1] + (sum[n] - sum[j - 1])), dp[i][j - 1][1] + (a[j] - a[j - 1]) * (sum[i - 1] + (sum[n] - sum[j - 1])));
// 对于关这个区间的灯有两种关法, 关左边和关右边,关左边有两种递推状态,一个是上一个区间
//关灯结束在左边,直接去关这个灯,另一个是在这个区间的右边,折返回来关这个灯,关右边同理
}
}
int ans = min(dp[1][n][0], dp[1][n][1]); // 最后可能的两种状态取最小值
printf("%d\n", ans);
return 0;
}