P4009 汽车加油行驶问题

传送门

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;
}

 

posted @ 2018-09-25 13:41  LLTYYC  阅读(347)  评论(0编辑  收藏  举报