不管是最短路还是网络流,都不好处理这个加油的过程
发 现 到 达 每 个 点 的 状 态 有 两 个 发现到达每个点的状态有两个 发现到达每个点的状态有两个
当前到达的花费和油量,这两个状态必须都要记录
有点子DP的味道了,事实上确实可以DP,但比较麻烦
图里面也有类似的问题--------分层图记录状态
把 图 分 为 k + 1 层 把图分为k+1层 把图分为k+1层
分 别 是 当 前 油 量 剩 下 k , k − 1 , k − 2 , . . . 0 的 时 候 分别是当前油量剩下k,k-1,k-2,...0的时候 分别是当前油量剩下k,k−1,k−2,...0的时候
这 样 一 来 连 边 就 非 常 清 晰 这样一来连边就非常清晰 这样一来连边就非常清晰
对 于 加 油 站 , 我 们 把 它 每 层 图 强 制 连 向 第 一 层 图 的 位 置 , 表 示 加 满 了 油 对于加油站,我们把它每层图强制连向第一层图的位置,表示加满了油 对于加油站,我们把它每层图强制连向第一层图的位置,表示加满了油
然 后 第 一 层 图 的 位 置 连 向 第 二 层 图 的 上 下 左 右 4 个 位 置 然后第一层图的位置连向第二层图的上下左右4个位置 然后第一层图的位置连向第二层图的上下左右4个位置
对 于 非 加 油 站 , 我 们 把 每 层 图 连 向 后 一 层 图 的 上 下 左 右 4 个 位 置 对于非加油站,我们把每层图连向后一层图的上下左右4个位置 对于非加油站,我们把每层图连向后一层图的上下左右4个位置
而 且 每 层 图 都 可 以 给 第 一 层 图 自 己 的 位 置 连 边 , 表 示 直 接 在 本 地 建 立 加 油 站 而且每层图都可以给第一层图自己的位置连边,表示直接在本地建立加油站 而且每层图都可以给第一层图自己的位置连边,表示直接在本地建立加油站
接下来是裸的最短路了
#include <bits/stdc++.h>
using namespace std;
const int maxn=6e5+10;
const int inf=1e9;
int n,m,k,a[209][209],id[209][209],top,dis[maxn],vis[maxn];
int A,B,C;
struct edge{
int to,w,nxt;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int w){
d[++cnt]=(edge){v,w,head[u]},head[u]=cnt;
}
void spfa()
{
queue<int>q;
for(int i=0;i<=(k+1)*n*n;i++) dis[i]=inf,vis[i]=0;
q.push( 1 ); dis[1]=0;
while( !q.empty() )
{
int u=q.front(); q.pop();
vis[u]=0;
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( dis[v]>dis[u]+d[i].w )
{
dis[v]=dis[u]+d[i].w;
if( !vis[v] )
vis[v]=1,q.push( v );
}
}
}
}
int main()
{
cin >> n >> k >> A >> B >> C;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
id[i][j]=++top;
cin >> a[i][j];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if( a[i][j] )
{
int u=id[i][j],v=id[i][j]+n*n;
if( j!=n ) add( u,v+1,0 );//第一层只能去第二层
if( j!=1 ) add( u,v-1,B );
if( i!=1 ) add( u,v-n,B );
if( i!=n ) add( u,v+n,0 );
for(int q=1;q<=k;q++)
add( u+q*n*n,u,A );//每层向第一层连边表示加油
continue;
}
for(int q=1;q<=k;q++)//q-1层连向q层
{
int u=id[i][j]+(q-1)*n*n,v=id[i][j]+q*n*n;
if( j!=n ) add( u,v+1,0 );//上下左右连边
if( j!=1 ) add( u,v-1,B );
if( i!=1 ) add( u,v-n,B );
if( i!=n ) add( u,v+n,0 );
add(u,id[i][j],C+A);//设立加油站回到第一层
if( q==k ) add(v,id[i][j],C+A);//最后一层也可以去第一层
}
}
spfa();
int minn=1e9;
for(int i=1;i<=k+1;i++ )
minn=min(minn,dis[i*n*n]);
cout << minn;
}