洛谷4009 汽车加油行驶问题 分层图最短路

版权声明:本文为博主原创文章,可以转载但是必须声明版权。 https://blog.csdn.net/forever_shi/article/details/82529732

题目链接
题意:
有一个n*n的网格,每次车沿格子走一格,有些格子有加油站,路过加油站必须加油,可以额外花c元在任意一个点加油,每次加了油之后能走k步,向上或者向左走要额外花b元,问从(1,1)到(n,n)的最小花费。

题解:
分k+1层建图,表示上次加了油之后当前已经走了k步,我们规定层数为0-k,图上的边权根据题意都比较容易确定,这里就简单介绍一下建边方法。对于每一层,如果到了一个加油站,那么边要从每一层向第0层的对应点连边;如果到达的点不是加油站,就往下一层的对应点连边。如果是第k层,那么只可以通过原有加油站或者多花c元在任意一点加油的方法再返回到第0层。之后就是从第0层的(1,1)节点开始跑最短路就行了。

代码:

c++
#include <bits/stdc++.h>
using namespace std;

int n,k,b,c,d,hed[2000010],cnt,dis[2000010],num[110][110],shu;
int ju[110][110],vis[2000010],ans=2e9;
struct node
{
    int to,dis,next;
}a[5000010];
priority_queue<pair<int,int> > q;
inline void add(int from,int to,int dis)
{
    a[++cnt].to=to;
    a[cnt].dis=dis;
    a[cnt].next=hed[from];
    hed[from]=cnt;
}
int main()
{
    scanf("%d%d%d%d%d",&n,&k,&b,&c,&d);
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=n;++j)
        {
            scanf("%d",&ju[i][j]);
            num[i][j]=++shu;
        }
    }
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=n;++j)
        {
            if(j>1)
            {
                int x=num[i][j],y=num[i][j-1],z=n*n;
                for(int l=0;l<=k-1;++l)
                {               
                    if(ju[i][j-1]!=1)
                    {
                        add(x+l*z,y+(l+1)*z,c);
                        add(x+l*z,x,b+d);
                    }
                    else
                    {
                        add(x+l*z,y,b+c);
                        add(x+l*z,x,b+d);
                    }
                }
                add(x+k*z,x,b+c+d);
            }
            if(j<n)
            {
                int x=num[i][j],y=num[i][j+1],z=n*n;
                for(int l=0;l<=k-1;++l)
                {               
                    if(ju[i][j+1]!=1)
                    add(x+l*z,y+(l+1)*z,0);
                    else
                    add(x+l*z,y,b);
                }
                add(x+k*z,x,b+d);
            }
            if(i>1)
            {
                int x=num[i][j],y=num[i-1][j],z=n*n;
                for(int l=0;l<=k-1;++l)
                {               
                    if(ju[i-1][j]!=1)
                    add(x+l*z,y+(l+1)*z,c);
                    else
                    add(x+l*z,y,b+c);
                }
                add(x+k*z,x,b+d);
            }
            if(i<n)
            {
                int x=num[i][j],y=num[i+1][j],z=n*n;
                for(int l=0;l<=k-1;++l)
                {               
                    if(ju[i+1][j]!=1)
                    add(x+l*z,y+(l+1)*z,0);
                    else
                    add(x+l*z,y,b);
                }
                add(x+k*z,x,b+d);
            }
        }
    }
    memset(dis,0x3f,sizeof(dis));
    dis[1]=0;
    q.push(make_pair(0,1));
    while(!q.empty())
    {
        int x=q.top().second;
        q.pop();
        if(vis[x])
        continue;
        vis[x]=1;
        for(int i=hed[x];i;i=a[i].next)
        {
            int y=a[i].to;
            if(dis[y]>dis[x]+a[i].dis)
            {
                dis[y]=dis[x]+a[i].dis;
                q.push(make_pair(-dis[y],y));
            }
        }
    }
    int x=num[n][n],y=n*n;
    for(int i=0;i<=k;++i)
    ans=min(ans,dis[i*y+x]);
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_shi/article/details/82529732