P1220 关路灯
链接
https://www.luogu.com.cn/problem/P1220
思路
之前想错了:直接用dp[i][j]表示消除ij内的代价。但是还得再加一维度:即dp[i][j][0]表示消除之后处在左端;dp[i][j][1]表示消除后处在右端。
很显然,消除完了之后只可能处于两端,不可能路过不关灯。
所以对dp[i][j][0]就有递推式:

dp[i][j][0] = min(dp[i+1][j][0]+consume,dp[i+1][j][1]+consume)
dp[i][j][1] = min(dp[i][j-1][0]+consume,dp[i][j-1][1]+consume)
(后一条原理同上图,没画出来)
然后还有就是这个consume要注意是没有熄灭的灯耗费的能量,所以排除掉诸如[i+1.j]的电灯后算出来的值。
还有就是遍历问题:如果i外j内双向,那么dp[i][j][0]会无法更新,所以采用j外i内,看代码。
参考dew题解:https://www.luogu.com.cn/problem/solution/P1220
代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define int long long
const int INF = LLONG_MAX;
const int N = 100;
int n, c;
int site[N], val[N];
int dp[N][N][2];
signed main()
{
IOS;
cin >> n >> c;
for (int i = 1; i <= n; i++)cin >> site[i] >> val[i];
for (int i = 1; i <= n; i++)val[i] += val[i - 1];
memset(dp, 0x3f, sizeof(dp));
dp[c][c][0] = dp[c][c][1] = 0;
for(int j = c; j <= n; j++)
for (int i=j-1;i>0;i--)
{
dp[i][j][0] = min(dp[i + 1][j][0] + (site[i + 1] - site[i]) * (val[n] - val[j] + val[i]),
dp[i + 1][j][1] + (site[j] - site[i]) * (val[n] - val[j] + val[i]));
dp[i][j][1] = min(dp[i][j - 1][0] + (site[j] - site[i]) * (val[n] - val[j - 1] + val[i - 1]),
dp[i][j - 1][1] + (site[j] - site[j - 1]) * (val[n] - val[j - 1] + val[i - 1]));
}
cout << min(dp[1][n][0], dp[1][n][1]);
return 0;
}

浙公网安备 33010602011771号