笔记 Building Shops

题意一开始都没看懂…
意思是造糖果屋,有造和不造两种选择。
造ai,ans+ci,不造,ans+d(此处与它最左边一个糖果屋);
很像01背包。所以定义dp状态 dp[ i ][ 0 ] 和dp[ i ] [ 1 ]分别代表i处造or不造的状态。
最后的答案是在造与不造之间决策,(ans=min(dp[ n ] [ 0 ] , dp[ n ][ 1 ])
看到好多种方法,慢慢研究

  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; 
  }
}
发布了24 篇原创文章 · 获赞 2 · 访问量 975

猜你喜欢

转载自blog.csdn.net/weixin_43521836/article/details/88553790