点此看题面

大致题意:给定一个\(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乱搞)的更多相关文章

  1. 洛谷 P4009 汽车加油行驶问题 解题报告

    P4009 汽车加油行驶问题 题目描述 给定一个\(N×N\)的方形网格,设其左上角为起点◎,坐标(1,1) ,\(X\)轴向右为正,\(Y\)轴向下为正,每个方格边长为1 ,如图所示. 一辆汽车从起 ...

  2. 洛谷P4009 汽车加油行驶问题

    题目描述 给定一个 N \times NN×N 的方形网格,设其左上角为起点◎,坐标(1,1)(1,1),XX 轴向右为正, YY 轴向下为正,每个方格边长为 11 ,如图所示. 一辆汽车从起点◎出发 ...

  3. 洛谷P4009 汽车加油行驶问题(分层最短路)

    传送门 说好的网络流24题呢……上次是状压dp,这次怎么又最短路了…… 不过倒是用这题好好学了一下分层图最短路 把每一个位置$(x,y)$,油量剩余$k$表示为一个状态,然后转化成一个$n$进制数,这 ...

  4. 洛谷P4009汽车加油行驶问题——网络流24题(最短路)

    题目:https://www.luogu.org/problemnew/show/P4009 网络流24题中不是网络流的最短路题: 把每个点拆成各个油量上的点,根据要求连边即可: 注意:点数最大为10 ...

  5. 洛谷 P4009 汽车加油行驶问题 【最小费用最大流】

    分层图,建k层,设(i,j,0)为点(i,j)的满油状态,全图的流量都是1,因为重复走到一个点没有意义.如果当前点是加油站,那么它向它上左的点连费用为a的边,向下右连费用为a+b的边: 否则,这个点的 ...

  6. 洛谷P5211 [ZJOI2017]字符串(线段树+乱搞)

    题面 传送门 题解 为什么大佬们全都是乱搞的--莫非这就是传说中的暴力能进队,乱搞能AC-- 似乎有位大佬能有纯暴力+玄学优化\(AC\)(不算上\(uoj\)的\(Hack\)数据的话--这要是放到 ...

  7. 洛谷 P1600 天天爱跑步(LCA+乱搞)

    传送门 我们把每一条路径拆成$u->lca$和$lca->v$的路径 先考虑$u->lca$,如果这条路径会对路径上的某一个点产生贡献,那么满足$dep[u]-dep[x]=w[x] ...

  8. P4009 汽车加油行驶问题

    P4009 汽车加油行驶问题 最短路 清一色的spfa....送上一个堆优化Dijkstra吧(貌似代码还挺短) 顺便说一句,堆优化Dj跑分层图灰常好写 #include<iostream> ...

  9. 【题解】【网络流24题】汽车加油行驶问题 [P4009] [Loj6223]

    [题解][网络流24题]汽车加油行驶问题 [P4009] [Loj6223] 传送门:汽车加油行驶问题 \([P4009]\) \([Loj6223]\) [题目描述] 给出一个 \(N \times ...

  10. 【网络流24题】 No.15 汽车加油行驶问题 (分层图最短路i)

    [题意] 问题描述:给定一个 N*N 的方形网格,设其左上角为起点◎, 坐标为( 1, 1), X 轴向右为正, Y轴向下为正, 每个方格边长为 1, 如图所示. 一辆汽车从起点◎出发驶向右下角终点▲ ...

随机推荐

  1. 玩转Android---组件篇---Intent(意图)

    Intent的中文意思是“意图,目的”的意思,可以理解为不同组件之间通信的“媒介”或者“信使”. 目标组件一般要通过Intent来声明自己的条件,一般通过组件中的<intent-filter&g ...

  2. 根据T-Code查看用户出口的代码

    在此非常非常感谢源作者,这段代码真的非常非常有用好用! REPORT  YLBTEST. TABLES :  tstc,     "SAP Transaction Codes(SAP 事务代 ...

  3. Pycharm自动部署项目

    Pycharm自动部署项目 大家好呀,又有几天不见各位了.断更了几天,给大家说声抱歉.清明节大家都挺忙的,有扫墓祭祖的,也有趁小长假去游玩的. 所以,在节后,更新也会照常进行,继续给大家分享本人的一些 ...

  4. 分层图最短路【bzoj2834】: 回家的路

    分层图最短路[bzoj2834]: 回家的路 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2834 这道题难在建边. 自己写的时候想到了 ...

  5. CF987A Infinity Gauntlet 模拟

    You took a peek on Thanos wearing Infinity Gauntlet. In the Gauntlet there is a place for six Infini ...

  6. thinkphp5.1页面页面模板及参数配置

    success和error跳转的模板在thinkphp/tpl/dispatch_jump.tpl 配置参数在thinkphp\library\traits\controller\jump.php文件 ...

  7. Github网站css加载不出来的处理方法(转,亲测有效)

    转载链接:https://blog.csdn.net/qq_36589706/article/details/80573008因为工作需求,自己会经常使用到github,但是突然有一天打开github ...

  8. haoi2018奇怪的背包题解

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=5302 对于一个物品,设它体积为v,那么,在背包参数为p的情况下,它能达到gcd(v,p ...

  9. P2375 [NOI2014]动物园 KMP

    好,暴力能拿$50pts\space qwq$ 暴力的思路就是一直跳$nxt[j]$,直到它的长度小于串的一半,然后开始计数,当然要接着跳$nxt[j]$ 正解:考虑没有长度要求的(不要求不重合)公共 ...

  10. 【ACM】阶乘之和 - 避免重复计算

    阶乘之和 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 给你一个非负数整数n,判断n是不是一些数(这些数不允许重复使用,且为正数)的阶乘之和,如9=1!+2!+3! ...