Atcoder abc の 初体験
[ABC320F] Fuel Round Trip
若只考虑单程的,设一个 \(dp_{i,j}\) 表示走到第 \(i\) 个加油站剩下的油为 \(j\) 的最小花费。
但是还需要考虑回来可能也要加油,所以综合考虑,设 \(dp_{i,j,k}\) 表示到第 \(i\) 个加油站去的途中有 \(j\) 的油量,归途有 \(k\) 的油量的最小花费。
考虑 \(dp_{i,j,k}\) 的转移,设 \(d=s_{i+1}-s_{i}\) :
若来回都不加,则 \(dp_{i+1,j-d,k+d}=min(dp_{i,j,k})\);
如果去的时候加,则 \(dp_{i+1,min(j+f_i,H)-d,k+d}=min(dp_{i,j,k}+p_i)\)
如果回的时候加,设下一个加油站时回时油量为 \(x\) ,则 \(min(x-d+f_i,H)=k\) 若 \(k<H\) 则 \(x=k+len-f_i\) ,若 \(k=H\) 则 \(x \geq H+d-f_i\) 转移就是 \(dp_{i+1,j-d,x}=min(dp_{i,j,k}+p_i)\)。
注意转移时第二维不要小于零,如果加油,转移的油量一定要大于加的油量。
复杂度 \(O(n*h^2)\) 。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=500;
int s[N];
int p[N],f[N];
int dp[N][N][N];
const int inf=2139062143;
signed main(){
int n,h;
scanf("%d%d",&n,&h);
int ma=0;
for(int i=1;i<=n;i++){
scanf("%d",&s[i]);
ma=max(ma,s[i]-s[i-1]);
}
if(ma>h){
cout<<"-1";
return 0;
}
for(int i=1;i<n;i++) scanf("%d%d",&p[i],&f[i]);
memset(dp,0x7f,sizeof(dp));
for(int i=0;i<=h;i++){
dp[0][h][i]=0;
}
for(int i=0;i<n;i++){
for(int j=0;j<=h;j++){
for(int k=0;k<=h;k++){
if(dp[i][j][k]==inf) continue;
int len=s[i+1]-s[i];
if(j-len>=0 && k+len<=h){
dp[i+1][j-len][k+len]=min(dp[i+1][j-len][k+len],dp[i][j][k]);
}
if(min(j+f[i],h)-len>=0 && k+len<=h){
dp[i+1][min(j+f[i],h)-len][k+len]=min(dp[i+1][min(j+f[i],h)-len][k+len],dp[i][j][k]+p[i]);
}
if(k<h){
if(j-len>=0 && k-f[i]+len<=h && k>=f[i]){
dp[i+1][j-len][k-f[i]+len]=min(dp[i+1][j-len][k-f[i]+len],dp[i][j][k]+p[i]);
}
}
else{
if(j-len>=0 && k>=f[i]){
for(int e=h+len-f[i];e<=h;e++){
dp[i+1][j-len][e]=min(dp[i+1][j-len][e],dp[i][j][k]+p[i]);
}
}
}
}
}
}
int ans=inf;
for(int i=0;i<=h;i++){
ans=min(ans,dp[n][i][i]);
}
if(ans==inf) cout<<"-1";
else cout<<ans<<endl;
}

浙公网安备 33010602011771号