网络流24题(十五)

网络流24题

十五、汽车加油行驶问题

题目描述

给定一个 \(N×N\) 的方形网格,设其左上角为起点\(◎\),坐标\((1,1)\)\(X\) 轴向右为正, \(Y\) 轴向下为正,每个方格边长为 \(1\) ,如图所示。

一辆汽车从起点\(◎\)出发驶向右下角终点\(▲\),其坐标为 \((N,N)\)

在若干个网格交叉点处,设置了油库,可供汽车在行驶途中加油。汽车在行驶过程中应遵守如下规则:

  1. 汽车只能沿网格边行驶,装满油后能行驶 \(K\) 条网格边。出发时汽车已装满油,在起点与终点处不设油库。

  2. 汽车经过一条网格边时,若其 \(X\) 坐标或 \(Y\) 坐标减小,则应付费用 \(B\) ,否则免付费用。

  3. 汽车在行驶过程中遇油库则应加满油并付加油费用 \(A\)

  4. 在需要时可在网格点处增设油库,并付增设油库费用 \(C\)(不含加油费用\(A\) )。

  5. \(N,K,A,B,C\) 均为正整数, 且满足约束: \(2\leq N\leq 100,2 \leq K \leq10\)

设计一个算法,求出汽车从起点出发到达终点所付的最小费用。

输入格式

文件的第一行是 \(N,K,A,B,C\) 的值。

第二行起是一个\(N\times N\)\(0−1\) 方阵,每行 \(N\) 个值,至 \(N+1\) 行结束。

方阵的第 \(i\) 行第 \(j\) 列处的值为 \(1\) 表示在网格交叉点 \((i,j)\) 处设置了一个油库,为 \(0\) 时表示未设油库。各行相邻两个数以空格分隔。

输出格式

程序运行结束时,输出最小费用。

题解

模型

所谓网络流24题就是24道不需要网络流做的题。
这又是一道最短路。
考虑油量分层,层数即为消耗油量。
\(dis[now][i][j]\)表示第\(now\)层,位置是\(i,j\)的最短路径。
建边就是
\(now\) == \(K\)时需要建立油库,相当于从\(dis[k][i][j]\)\(dis[0][i][j]\)连接一条权值为\(a+c\)的边。
当此处有加油站的时候会被强制收费,只要\(now>0\)。就连边权\(a\)的边。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
int dis[110][110][15],init[110][110][15];
int n,k,a,b,c,ma[110][110];
struct node
{
    int x,y,k;
};
queue<node> q;
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
int main()
{
    scanf("%d%d%d%d%d",&n,&k,&a,&b,&c);
    for(int i=1;i<=n;++i)
    for(int j=1;j<=n;++j) scanf("%d",&ma[i][j]);
    memset(dis,20,sizeof(dis));
    dis[1][1][k]=0;init[1][1][k]=1;
    q.push((node){1,1,k});
    while(!q.empty())
    {
        int X=q.front().x;
        int Y=q.front().y;
        int K=q.front().k;q.pop();
//        cout<<"("<<X<<","<<Y<<")"<<" :"<<K<<"   "<<dis[X][Y][K]<<endl;
        init[X][Y][K]=0;
        if(ma[X][Y]&&K!=k)//加油 
        {
            if(dis[X][Y][k]>dis[X][Y][K]+a)
            {
                dis[X][Y][k]=dis[X][Y][K]+a;
                if(!init[X][Y][k])
                init[X][Y][k]=1,q.push((node){X,Y,k});
            }
            continue;
        } 
        else
        {
            if(dis[X][Y][k]>dis[X][Y][K]+a+c)
            {
                dis[X][Y][k]=dis[X][Y][K]+a+c;
                if(!init[X][Y][k])
                init[X][Y][k]=1,q.push((node){X,Y,k});
            }
        }
        if(K>0)//开车 
        for(int i=0;i<4;++i)
        {
            int x=X+dx[i];
            int y=Y+dy[i];
            if(x<1||x>n||y<1||y>n) continue;
            int len=0;
            if(x<X||y<Y) len=b;
            if(dis[x][y][K-1]>dis[X][Y][K]+len)
            {
                dis[x][y][K-1]=dis[X][Y][K]+len;
                if(!init[x][y][K-1])
                init[x][y][K-1]=1,q.push((node){x,y,K-1});
            }
        }
    }
    int ans=(1<<30);
    for(int i=0;i<=k;++i)
    ans=min(ans,dis[n][n][i]);
    printf("%d\n",ans);
    return 0;
}
posted @ 2021-10-25 22:38  Paranoid5  阅读(47)  评论(0编辑  收藏  举报