汽车加油行驶问题 题解
作者:互联网
题目描述
给定一个 \(N \times N\) 的方形网格,设其左上角为起点◎,坐标\((1,1)\),\(X\) 轴向右为正, \(Y\) 轴向下为正,每个方格边长为 \(1\) ,如图所示。
一辆汽车从起点◎出发驶向右下角终点▲,其坐标为 \((N,N)\)。
在若干个网格交叉点处,设置了油库,可供汽车在行驶途中加油。汽车在行驶过程中应遵守如下规则:
-
汽车只能沿网格边行驶,装满油后能行驶 \(K\) 条网格边。出发时汽车已装满油,在起点与终点处不设油库。
-
汽车经过一条网格边时,若其 \(X\) 坐标或 \(Y\) 坐标减小,则应付费用 \(B\) ,否则免付费用。
-
汽车在行驶过程中遇油库则应加满油并付加油费用 \(A\)。
-
在需要时可在网格点处增设油库,并付增设油库费用 \(C\)(不含加油费用\(A\) )。
-
\(N,K,A,B,C\) 均为正整数, 且满足约束: \(2\leq N\leq 100,2 \leq K \leq 10\)。
设计一个算法,求出汽车从起点出发到达终点所付的最小费用。
输入格式
文件的第一行是 \(N,K,A,B,C\) 的值。
第二行起是一个\(N\times N\) 的 \(0-1\) 方阵,每行 \(N\) 个值,至 \(N+1\) 行结束。
方阵的第 \(i\) 行第 \(j\) 列处的值为 \(1\) 表示在网格交叉点 \((i,j)\) 处设置了一个油库,为 \(0\) 时表示未设油库。各行相邻两个数以空格分隔。
输出格式
程序运行结束时,输出最小费用。
样例输入
9 3 2 3 6
0 0 0 0 1 0 0 0 0
0 0 0 1 0 1 1 0 0
1 0 1 0 0 0 0 1 0
0 0 0 0 0 1 0 0 1
1 0 0 1 0 0 1 0 0
0 1 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0 1
1 0 0 1 0 0 0 1 0
0 1 0 0 0 0 0 0 0
样例输出
12
数据范围:\(2 \leq n \leq 100,2 \leq k \leq 10\)
分层图板子题了属于是吧,思路非常简单粗暴,主要注意建图的hash问题,容易出现疏漏。
图分为 \(k+1\) 层,箭头所指可以直达,蓝线自下而上需要付费(即最短路边权,费用流费用),黄线自高层连到基层需要付费(同上),最后在每一层的右下扫一遍取最小值即可。
摘自洛谷用户:Adove
注意细节:到达加油站有两种情况
-
非满油,花 \(A\) 加油。
-
满油,正常向四周转移。
Code.
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10,M=N*5;
int n,k,a,b,c,idx,h[M],ne[M],e[M],w[M],dis[M];
bool st[M];
void add(int x,int y,int z,int xx,int yy,int zz,int c)
{
int u=n*n*(z-1)+(x-1)*n+y,v=n*n*(zz-1)+(xx-1)*n+yy;
ne[++idx]=h[u],e[idx]=v,w[idx]=c,h[u]=idx;
}
void spfa()
{
for(int i=0;i<=(n*n*(k+1));i++) dis[i]=0x3f3f3f3f;
queue<int> q;
dis[1]=0;st[1]=1;q.push(1);
while(!q.empty())
{
int u=q.front();q.pop();
st[u]=0;
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(dis[j]>dis[u]+w[i])
{
dis[j]=dis[u]+w[i];
if(!st[j]) q.push(j),st[j]=1;
}
}
}
}
int main()
{
memset(h,-1,sizeof h);
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++)
{
int x;
scanf("%d",&x);
for(int kk=1;kk<=k;kk++) add(i,j,kk,i,j,kk+1,0);
if(x)
{
for(int kk=2;kk<=k+1;kk++) add(i,j,kk,i,j,1,a);
if(i < n) add(i,j,1,i+1,j,2,0);
if(j < n) add(i,j,1,i,j+1,2,0);
if(i > 1) add(i,j,1,i-1,j,2,b);
if(j > 1) add(i,j,1,i,j-1,2,b);
}
else
{
for(int kk=1;kk<=k;kk++)
{
if(i < n) add(i,j,kk,i+1,j,kk+1,0);
if(j < n) add(i,j,kk,i,j+1,kk+1,0);
if(i > 1) add(i,j,kk,i-1,j,kk+1,b);
if(j > 1) add(i,j,kk,i,j-1,kk+1,b);
}
for(int kk=2;kk<=k+1;kk++) add(i,j,kk,i,j,1,a+c);
}
}
spfa();
int ans=0x3f3f3f3f;
for(int i=1;i<=k+1;i++) ans=min(ans,dis[n*n*i]);
printf("%d",ans);
return 0;
}
标签:leq,int,题解,网格,行驶,kk,油库,加油,dis 来源: https://www.cnblogs.com/EastPorridge/p/16380368.html