本来想练一手费用流的 但是一看这个题分层图跑的更快 而且也是个很好的分层图板子
将图分为k+1层 因为充满油可以跑k条边 算上 开始的1 就是k+1层
首先 第x层图中的点[i,j] 连向第x+1层的点[i,j]的 边权为 0
如果该点不是加油站 第x层[i,j] 连向第x+1层[i,j+1] [i+1,j]边权为0
连向第x+1层[i-1,j] [i,j-1]边权为b
如果设该点为加油站 第x层[i,j] 连向 第1层 [i,j]边权为p+c
如果该点为加油站 第x层[i,j] 连向 第1层 [i,j] 边权为p
第x层[i,j] 连向 第2层 [i,j+1] [i+1,j] 边权为0
连向 第2层 [i-1,j] [i,j-1] 边权为b
注意题目要求遇到油库就要加满油
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF=2e9;
int n,k,p,b,c,np;
int h[350005],ln[350005],q[900005];
bool vis[350005],oil;
struct rpg{
int li,nx,ln;
}a[900005];
void add(int x1,int y1,int z1,int x2,int y2,int z2,int ln){
int ls=n*n*(z1-1)+(x1-1)*n+y1,nx=n*n*(z2-1)+(x2-1)*n+y2;
a[++np]=(rpg){h[ls],nx,ln};
h[ls]=np;
}
void spfa(){
for(int i=1;i<=n*n*(k+1);++i) ln[i]=INF;
int hd=1,tl=1;
q[hd]=1;
ln[1]=0;
while(hd<=tl){
int nw=q[hd++];
vis[nw]=0;
for(int i=h[nw];i;i=a[i].li){
if(ln[a[i].nx]>ln[nw]+a[i].ln){
ln[a[i].nx]=ln[nw]+a[i].ln;
if(!vis[a[i].nx]){
vis[a[i].nx]=1;
q[++tl]=a[i].nx;
}
}
}
}
}
int main(){
scanf("%d%d%d%d%d",&n,&k,&p,&b,&c);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
scanf("%d",&oil);
for(int l=1;l<=k;++l){
add(i,j,l,i,j,l+1,0);
}
if(oil){
for(int l=2;l<=k+1;++l){
add(i,j,l,i,j,1,p);
}
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 l=1;l<=k;++l){
if(i<n) add(i,j,l,i+1,j,l+1,0);
if(j<n) add(i,j,l,i,j+1,l+1,0);
if(i>1) add(i,j,l,i-1,j,l+1,b);
if(j>1) add(i,j,l,i,j-1,l+1,b);
}for(int l=2;l<=k+1;++l){
add(i,j,l,i,j,1,p+c);
}
}
}
}spfa();
int ans=INF;
for(int i=1;i<=k+1;++i) ans=min(ans,ln[n*n*i]);
printf("%d\n",ans);
return 0;
}