思考一会发现,假设dp[i]意为前i+1天旅行所需的最低费用,也就是从前往后进行dp,发现不好找到状态转移方程。
观察思考发现,由于每一张通行证都是购买后生效,所以每一张通行证都具有“后对前后无效性”
eg:第10天买与不买、买啥通行证,不会影响前9天买啥通行证,但是前9天买的通行证会影响第10天买不买、买啥通行证
因此,我们采用从后往前的dp
dp[i]:后365-i+1天的最小花费
优化一下:上述dp[i]意思中,包含了365天,但是题目给出的数据很多并不是第365天还要旅游(也就是d[n-1]并不都是365),因此我们可以让dp[i]意为:后d[n-1]-i+1天的最小花费,因此节省了空间。
再优化一下:在判断某一天是不是要旅行时,由于题目给出 d中数字大小严格递增 的条件,因此判断第i天是否旅行时,如果遍历到d中某个元素已经>i了,说明第i天不旅行,因此就可以跳出遍历
再再优化一下:还是在判断某一天是不是要旅行时,如果第d[j]天已经被访问到了(i等于过d[j]了),那么下一次访问到的旅游的天就是d[j-1],因此之后只需判断 i 是否等于d[j-1]即可,每一次访问到d[j],就让j--,注意不要越界
给出最终代码,有几率可以打败全世界的人QAQ
int min3(int a,int b,int c){
int temp=a<b?a:b;
return temp<c?temp:c;
}
int mincostTickets(vector<int>& d, vector<int>& c) {
int n=d.size();
vector<int> dp(d[n-1]+40);
dp[d[n-1]]=min3(c[0],c[1],c[2]);
int j=n-2;
for(int i=d[n-1]-1;i>=1;i--){
/*bool flag=false;
for(int j=0; j<n-1 ;j++){
if(d[j]>i)
break;
if(i==d[j]){
dp[i]=min3(c[0]+dp[i+1],c[1]+dp[i+7],c[2]+dp[i+30]);
flag=true;
break;
}
}
if(!flag){
dp[i]=dp[i+1];
}*/ //这是第一次优化后的源代码
if(j<0 || i!=d[j]){
dp[i]=dp[i+1];
}
else{
dp[i]=min3(c[0]+dp[i+1],c[1]+dp[i+7],c[2]+dp[i+30]);
j--;
} //这是第二次优化后的更改代码
}
return dp[1];
}