题意一开始都没看懂…
意思是造糖果屋,有造和不造两种选择。
造ai,ans+ci,不造,ans+d(此处与它最左边一个糖果屋);
很像01背包。所以定义dp状态 dp[ i ][ 0 ] 和dp[ i ] [ 1 ]分别代表i处造or不造的状态。
最后的答案是在造与不造之间决策,(ans=min(dp[ n ] [ 0 ] , dp[ n ][ 1 ])
看到好多种方法,慢慢研究
- 法(一)
#include <iostream>
#include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
struct p{
//注意数据范围啊!老是被坑
long long int x, c;
};
//给的数据没有排好序
bool cmp(p p1,p p2){
return p1.x<p2.x;
}
int n;
//dp数组
long long dp[3001][2];
p a[3001];
int main(){
while(cin >> n){
memset(dp,0,sizeof(dp));
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++){
cin>> a[i].x >> a[i].c;
}
sort(a+1,a+1+n,cmp);
//最左边一定要造一个,也就是第一个
dp[1][1] = a[1].c;
//dp[ i ] [ 0 ]代表i处不建造的情况,初始化为inf:因为后面要根据dp[i -1][ 0 or 1 ]的情况推导
dp[1][0]=inf;
for(int i=2;i<=n;i++){
//判断i处建造的最优解:由前一个的最优状态得到
dp[i][1]=min(dp[i-1][0],dp[i-1][1])+ a[i].c;
dp[i][0]=inf;
long long sum=0;
for(int j=i-1;j>=1;j--){
//sum是用来计算距离总和的
/*
已知i处不建
j枚举的最近糖果屋,每段都算了一次,
比如
j=i-1时,1*d(a[i],a[i-1]) i~i-1算了一次
j=i-2时,2*d(a[i-1],a[i-2]) i~i-2算了一次,i-1~i-2算了一次
依此类推,可计算得到总和
节省时间 一个很有意思的想法,像数列求和时用的
s1+s2+s3+...+sn = a1*n+ a2 *(n-1) + a3*(n-2)+...+an一样的想法,不用再分别计算s1到sn的值了
适用于排好序的情况
*/
sum += (i-j)*(a[j+1].x - a[j].x);
//不断更新,得到i处不建时的最优解,也就是找到最合适的j作为离它最近的糖果屋,来使cost最小
dp[i][0]=min(dp[j][1]+sum,dp[i][0]);
}
}
long long ans = min(dp[n][1],dp[n][0]);
cout<< ans <<endl;
}
}