比较好的一道题吧。。。。。转移方程有点长(是我太弱了。。)
嘛,,,记得第一次见到这个题是在初二。。。。的时候。。。然后当时就被这个题劝退了
。。。。结果现在看起来也挺简单的啊。。。。。。。。。
嘛,只要考虑 状态怎么设立,这题就可以解决了。。。。
发现 子问题在这里,相当于是之前关灯区间。。。。。继承过来。。。。那么不一定要把最后一次关灯的位置记录下来。。
可以尝试一下(类似与预支答案的操作)直接记录最后是在右段点结束还是左端点结束。。。。
然后就可以直接把答案算出来了。。。
#include<bits/stdc++.h>
#define MAXN 50
using namespace std;
int n,c,sum[MAXN+5],f[MAXN+5][MAXN+5][3],tot;
//预处理出求和函数
struct node{
int dx,dy;
}light[MAXN+5];
bool cmp(node x,node y){
return x.dx<y.dx;
}
void init(){
cin>>n>>c;
for(int i = 1 ; i <= n ; i++)cin>>light[i].dx>>light[i].dy;
sort(light+1,light+1+n,cmp);
for(int i = 1 ; i <= n ; i++)sum[i] = sum[i-1] + light[i].dy;
memset(f,0x7f,sizeof(f));tot = sum[n];
f[c][c][0] = f[c][c][1] = 0;
}
int cal(int l,int r){
return tot - (sum[r] - sum[l - 1]);
}
int jl(int l,int r){
return light[r].dx - light[l].dx;
}
void solve(){
for(int len = 2 ; len <= n ; len++){
for(int i = 1 ; i+len-1 <= n ;i++){
int j = i+len-1;
//在左边的转移
f[i][j][0] = min(f[i][j][0] , f[i+1][j][0] + jl(i,i+1) * cal(i+1,j));//i+1 从左到左 转移前在i+1
f[i][j][0] = min(f[i][j][0] , f[i+1][j][1] + jl(i,j) * cal(i+1,j));//i+1 从右到左 转移前在j
f[i][j][0] = min(f[i][j][0] , f[i][j-1][0] + jl(i,j) * cal(i,j-1) + jl(i,j) * cal(i,j));//j-1 从左到右再到左 转移前在i
f[i][j][0] = min(f[i][j][0] , f[i][j-1][1] + jl(j-1,j) * cal(i,j-1) + jl(i,j) * cal(i,j));//j-1 从右边去j然后再回到左 转移前在j-1
//在右边的转移
f[i][j][1] = min(f[i][j][1] , f[i+1][j][0] + jl(i,i+1) * cal(i+1,j) + jl(i,j) * cal(i,j));//转移前在i+1 现在要去i 然后再去j
f[i][j][1] = min(f[i][j][1] , f[i+1][j][1] + jl(i,j) * cal(i+1,j) + jl(i,j) * cal(i,j));//转移前在j ——》i——》j
f[i][j][1] = min(f[i][j][1] , f[i][j-1][0] + jl(i,j) * cal(i,j-1));//转移前在i 现在去就j
f[i][j][1] = min(f[i][j][1] , f[i][j-1][1] + jl(j-1,j) * cal(i,j-1));//转移前在j-1 然后要去j
}
}
cout<<min(f[1][n][0] , f[1][n][1])<<endl;
}
int main(){
init();
solve();
}
dp式子好工整。。。。