N和K都不大
可以跑分层图
设dis[ i ] [ j ] [ k ] 表示从起点到坐标为 i , j 的点,还剩下可以跑 k 步的油时的最少花费
然后用 Dijkstra 跑分层图
走下一步时就分开来讨论每种可能的操作
但是一定要注意每种操作的顺序
先走,然后考虑走到的这点要不要设加油站,再考虑走到的这点有没有加油站
如果有加油站,就一定要交钱(强买强卖...)
发现题目没说每个油库是不是只能用一次
但是为了最优解显然不能重复用
所以根本不用考虑之前新设立了哪些加油站
细节在代码
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #include<queue> using namespace std; int n,K,A,B,C; int xx[4]={0,1,0,-1},yy[4]={1,0,-1,0}; int dis[107][107][17]; int mp[107][107];//存地图状态 struct node { int x,y,gas,cost; bool operator < (const node &b) const{ return cost>b.cost; } }; priority_queue <node> q; void Dijk() { memset(dis,0x7f,sizeof(dis)); q.push((node){1,1,K,0}); dis[1][1][K]=0;//一开始油是满的,题目限制起点和终点没有油库 while(!q.empty()) { node u=q.top(); q.pop(); if(u.cost!=dis[u.x][u.y][u.gas]||!u.gas) continue;//如果没有油了就不能再走,新设油库再加油的操作上一步已经考虑过了 for(int k=0;k<4;k++) { int x=u.x+xx[k],y=u.y+yy[k],cost=u.cost; if(!x||!y||x>n||y>n) continue;//判断越界 if(x<u.x||y<u.y) cost+=B;//题目要求 if(mp[x][y]&&dis[x][y][K]>cost+A) q.push( (node){x,y,K,dis[x][y][K]=cost+A} );//如果有油库一定要加油 if(!mp[x][y]) { if(dis[x][y][u.gas-1]>cost) q.push( (node){x,y,u.gas-1,dis[x][y][u.gas-1]=cost} );//不设油库 if(dis[x][y][K]>cost+A+C) q.push( (node){x,y,K,dis[x][y][K]=cost+A+C} );//设油库 } } } } int main() { cin>>n>>K>>A>>B>>C; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&mp[i][j]); Dijk(); int ans=2e9+7; for(int i=0;i<=K;i++) ans=min(ans,dis[n][n][i]);//从终点的所有状态里找最优解,当然包括油为0的状态 printf("%d",ans); return 0; }