【洛谷4009】汽车加油行驶问题(SPFA乱搞)
大致题意:给定一个\(N*N\)的方形网格,其中1表示这个格子有油库,0表示这个格子没油库,且汽车加满油可以行驶\(k\)条网格边。如果遇到油库必须加满油并花费\(A\)元,如果\(X\)坐标或\(Y\)坐标减少需花费\(B\)元,若需新建一个油库需花费\(C\)元(另需加油费\(A\)元)。问你从\((1,1)\)到\((N,N)\)的最少花费。
\(SPFA\)做法
先说明,这篇博客只讲\(SPFA\),不讲网络流。
我们可以用\(dis_{i,j,l}\)来表示到达网格\((i,j)\),还能行驶\(l\)条网格边所需的最小花费。
显然,初始化\(dis_{1,1,k}=0\),然后从\((1,1)\)出发跑最短路即可。
对于当前状态\((i,j,l)\),我们可以这样考虑它的转移:
如果当前还能行驶的距离不等于\(k\)(即油未加满)
如果当前网格有油库,那么我们就可以花费\(A\)元将状态转移至\((i,j,k)\),即:
\[dis_{i,j,k}=min(dis_{i,j,k},dis_{i,j,l}+A)
\]如果当前网格没有油库,那么我们就可以花费\(C\)元造一个油库,然后花费\(A\)元将状态转移至\((i,j,k)\),即:
\[dis_{i,j,k}=min(dis_{i,j,k},dis_{i,j,l}+A+C)
\]
如果当前还能行驶的距离大于0
- 如果是向右或向下行驶,那么可以直接将状态转移至\((i+1,j,l-1)\)和\((i,j+1,l-1)\),即:
\[dis_{i+1,j,l-1}=min(dis_{i+1,j,l-1},dis_{i,j,l})
\]\[dis_{i,j+1,l-1}=min(dis_{i,j+1,l-1},dis_{i,j,l})
\]如果是向左或向上行驶,那么就需要花费\(B\)元才能将状态转移至\((i-1,j,l-1)\)和\((i,j-1,l-1)\),即:
\[dis_{i-1,j,l-1}=min(dis_{i-1,j,l-1},dis_{i,j,l}+B)
\]\[dis_{i,j-1,l-1}=min(dis_{i,j-1,l-1},dis_{i,j,l}+B)
\]
这样,代码就不难写了吧。
代码
#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)<0?-(x):(x))
#define LL long long
#define ull unsigned long long
#define swap(x,y) (x^=y,y^=x,x^=y)
#define tc() (A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++)
#define pc(ch) (pp_<100000?pp[pp_++]=(ch):(fwrite(pp,1,100000,stdout),pp[(pp_=0)++]=(ch)))
#define N 100
#define K 10
#define MOD (N*N*K)
int pp_=0;char ff[100000],*A=ff,*B=ff,pp[100000];
using namespace std;
const int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int n,m,a,b,c,s[N+5][N+5],dis[N+5][N+5][K+5],Inqueue[N+5][N+5][K+5];
struct Status
{
int x,y,v;
}q[MOD+5];
inline void read(int &x)
{
x=0;static char ch;
while(!isdigit(ch=tc()));
while(x=(x<<3)+(x<<1)+ch-48,isdigit(ch=tc()));
}
inline void read_digit(int &x)
{
while(!isdigit(x=tc()));
x-=48;
}
inline void write(int x)
{
if(x>9) write(x/10);
pc(x%10+'0');
}
int main()
{
register int i,j,l,H=Inqueue[1][1][m]=1,T=1;
for(read(n),read(m),read(a),read(b),read(c),i=1;i<=n;++i) for(j=1;j<=n;++j) read_digit(s[i][j]);
for(i=1;i<=n;++i) for(j=1;j<=n;++j) for(l=0;l<=m;++l) dis[i][j][l]=1e9;//初始化
dis[1][1][m]=0,q[1]=(Status){1,1,m};//初始化
while((H%=MOD)^(T+1))//只要队列不为空(因为是手写的循环队列,因此看起来特别别扭)
{
Status k=q[H++];Inqueue[k.x][k.y][k.v]=0;//取出队首元素
if(k.v^m)//如果油未加满
{
if(s[k.x][k.y])//如果这里有油库
{
if(dis[k.x][k.y][k.v]+a<dis[k.x][k.y][m])
{
dis[k.x][k.y][m]=dis[k.x][k.y][k.v]+a;
if(!Inqueue[k.x][k.y][m]) Inqueue[k.x][k.y][m]=1,q[(++T)%=MOD]=(Status){k.x,k.y,m};
}
continue;
}//否则就没有油库,需要花C元建一个
if(dis[k.x][k.y][k.v]+a+c<dis[k.x][k.y][m])
{
dis[k.x][k.y][m]=dis[k.x][k.y][k.v]+a+c;
if(!Inqueue[k.x][k.y][m]) Inqueue[k.x][k.y][m]=1,q[(++T)%=MOD]=(Status){k.x,k.y,m};
}
}
if(k.v)//如果还有油
{
for(i=0;i<4;++i)//枚举上下左右四个方向
{
static int nx,ny;
if(dis[k.x][k.y][k.v]+(dx[i]<0||dy[i]<0)*b<dis[nx=k.x+dx[i]][ny=k.y+dy[i]][k.v-1])//如果是向左或向上,还需加上B元
{
dis[nx][ny][k.v-1]=dis[k.x][k.y][k.v]+(dx[i]<0||dy[i]<0)*b;
if(!Inqueue[nx][ny][k.v-1]) Inqueue[nx][ny][k.v-1]=1,q[(++T)%=MOD]=(Status){nx,ny,k.v-1};
}
}
}
}
register int ans=1e9;
for(i=0;i<=m;++i) ans=min(ans,dis[n][n][i]);//枚举到达(N,N)后还能行驶的距离,从而求出最优方案下的最少花费
return write(ans),fwrite(pp,1,pp_,stdout),0;
}
【洛谷4009】汽车加油行驶问题(SPFA乱搞)的更多相关文章
- 洛谷 P4009 汽车加油行驶问题 解题报告
P4009 汽车加油行驶问题 题目描述 给定一个\(N×N\)的方形网格,设其左上角为起点◎,坐标(1,1) ,\(X\)轴向右为正,\(Y\)轴向下为正,每个方格边长为1 ,如图所示. 一辆汽车从起 ...
- 洛谷P4009 汽车加油行驶问题
题目描述 给定一个 N \times NN×N 的方形网格,设其左上角为起点◎,坐标(1,1)(1,1),XX 轴向右为正, YY 轴向下为正,每个方格边长为 11 ,如图所示. 一辆汽车从起点◎出发 ...
- 洛谷P4009 汽车加油行驶问题(分层最短路)
传送门 说好的网络流24题呢……上次是状压dp,这次怎么又最短路了…… 不过倒是用这题好好学了一下分层图最短路 把每一个位置$(x,y)$,油量剩余$k$表示为一个状态,然后转化成一个$n$进制数,这 ...
- 洛谷P4009汽车加油行驶问题——网络流24题(最短路)
题目:https://www.luogu.org/problemnew/show/P4009 网络流24题中不是网络流的最短路题: 把每个点拆成各个油量上的点,根据要求连边即可: 注意:点数最大为10 ...
- 洛谷 P4009 汽车加油行驶问题 【最小费用最大流】
分层图,建k层,设(i,j,0)为点(i,j)的满油状态,全图的流量都是1,因为重复走到一个点没有意义.如果当前点是加油站,那么它向它上左的点连费用为a的边,向下右连费用为a+b的边: 否则,这个点的 ...
- 洛谷P5211 [ZJOI2017]字符串(线段树+乱搞)
题面 传送门 题解 为什么大佬们全都是乱搞的--莫非这就是传说中的暴力能进队,乱搞能AC-- 似乎有位大佬能有纯暴力+玄学优化\(AC\)(不算上\(uoj\)的\(Hack\)数据的话--这要是放到 ...
- 洛谷 P1600 天天爱跑步(LCA+乱搞)
传送门 我们把每一条路径拆成$u->lca$和$lca->v$的路径 先考虑$u->lca$,如果这条路径会对路径上的某一个点产生贡献,那么满足$dep[u]-dep[x]=w[x] ...
- P4009 汽车加油行驶问题
P4009 汽车加油行驶问题 最短路 清一色的spfa....送上一个堆优化Dijkstra吧(貌似代码还挺短) 顺便说一句,堆优化Dj跑分层图灰常好写 #include<iostream> ...
- 【题解】【网络流24题】汽车加油行驶问题 [P4009] [Loj6223]
[题解][网络流24题]汽车加油行驶问题 [P4009] [Loj6223] 传送门:汽车加油行驶问题 \([P4009]\) \([Loj6223]\) [题目描述] 给出一个 \(N \times ...
- 【网络流24题】 No.15 汽车加油行驶问题 (分层图最短路i)
[题意] 问题描述:给定一个 N*N 的方形网格,设其左上角为起点◎, 坐标为( 1, 1), X 轴向右为正, Y轴向下为正, 每个方格边长为 1, 如图所示. 一辆汽车从起点◎出发驶向右下角终点▲ ...
随机推荐
- Unity3D -- shader语法内置函数
该篇是Unity Shader中HLSL的内置函数,主要是一些数学方面的计算函数.在写Shader的时候可以直接使用. abs //计算输入值的绝对值. acos //返回输入值反余弦值. all / ...
- Tomcat&Servlet
Tomcat&Servlet 一.web开发相关的概念 1. 软件架构 1.1 C/S架构 C:Client客户端, S:Server服务器 比如:QQ.微信.大型网游 优点: 显示效果炫 安 ...
- spring data之JDBCTemplate学习笔记
一.spring 数据访问哲学 1.为避免持久化的逻辑分散在程序的各个组件中,数据访问的功能应到放到一个或多个专注于此的组件中,一般称之为数据访问对象(data access object,DAO). ...
- 方程的解_NOI导刊2010提高(01) 组合数
题目描述 佳佳碰到了一个难题,请你来帮忙解决. 对于不定方程a1+a2+…+ak-1+ak=g(x),其中k≥2且k∈N,x是正整数,g(x)=x^x mod 1000(即x^x除以1000的余数), ...
- 移动端APP第一次登录和自动登录流程
App登陆保存数据流程App因为要实现自动登陆功能,所以必然要保存一些凭据,所以比较复杂. App登陆要实现的功能: 密码不会明文存储,并且不能反编绎解密: 在服务器端可以控制App端的登陆有效性,防 ...
- 【ACM】最少乘法次数 - 树
最少乘法次数 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 给你一个非零整数,让你求这个数的n次方,每次相乘的结果可以在后面使用,求至少需要多少次乘.如24:2*2 ...
- jquery——元素节点操作
插入节点: 1.append()和appendTo():在现存元素的内部,从后面插入元素 <script type="text/javascript"> $(funct ...
- Docker | 第六章:构建私有仓库
前言 上一章节,讲解了利用Dockerfile和commit进行自定义镜像的构建.大部分时候,公司运维或者实施部门在构建了符合公司业务的镜像环境后,一般上不会上传到公共资源库的.这就需要自己搭建一个私 ...
- MySQL中有关TIMESTAMP和DATETIME的对比
TIMESTAMP和DATETIME的相同点: 1> 两者都可用来表示YYYY-MM-DD HH:MM:SS[.fraction]类型的日期. TIMESTAMP和DATETIME的不同点: 1 ...
- 设计模式--观察者模式(KVO)
观察者模式(Observer):观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 举个例子, ...