点此看题面

大致题意:给定一个\(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. Ubuntu常用命令集合

    文件操作 查看当前目录: pwd 参考文章:https://blog.csdn.net/qq_33421080/article/details/76551554 应用编辑类 安装: sudo apt- ...

  2. CF 979D Kuro and GCD and XOR and SUM(异或 Trie)

    CF 979D Kuro and GCD and XOR and SUM(异或 Trie) 给出q(<=1e5)个操作.操作分两种,一种是插入一个数u(<=1e5),另一种是给出三个数x, ...

  3. Ubuntu系统配置的一些要点

    硬盘安装时必须先卸载光驱! 安装时如果是uefi,应该把引导驱动器设为windows所在的硬盘,否则设为整个硬盘..然后就可以用easybcd来设置windows下的引导. unity tweak t ...

  4. MCP|DYM|Quantitative mass spectrometry to interrogate proteomic heterogeneity in metastatic lung adenocarcinoma and validate a novel somatic mutation CDK12-G879V (利用定量质谱探究转移性肺腺瘤的蛋白质组异质性及验证新体细胞突变)

    文献名:Quantitative mass spectrometry to interrogate proteomic heterogeneity in metastatic lung adenoca ...

  5. 开发外包注意事项——iOS APP的开发

    1. APP外包的流程是怎样的? 一般外包的项目都需要经常这几个流程: 1)需求沟通:双方沟通项目的需求,对项目的可行性进行分析 2)工作量评估:在确认了项目的需求后,外包团队对项目的价钱和进度进行评 ...

  6. 对sass通过compass进行编译

    1.创建一个Compass项目:compass create myproject 其中myproject是项目名称.2.编写scss文件.3.编译成css文件:①:Compass的编译命令是:comp ...

  7. java日期与时间戳相互转换大全

    转载大神 https://blog.csdn.net/djc777/article/details/50904989/

  8. LeetCode 208 Implement Trie (Prefix Tree) 字典树(前缀树)

    Implement a trie with insert, search, and startsWith methods.Note:You may assume that all inputs are ...

  9. LeetCode 236 Lowest Common Ancestor of a Binary Tree 二叉树两个子节点的最低公共父节点

    /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode ...

  10. Ubuntu apt-get update中断的时候会出现一个错误导致不能再apt-get update

    错误描述为:Could not get lock /var/lib/apt/lists/lock - open (11: Resource temporarily unavailable) E: Un ...