题目要满足三个条件:
1:汽车经过一条网格边时,若其 X 坐标或 Y 坐标减小,则应付费用 B ,否则免付费用。
2:汽车在行驶过程中遇油库则应加满油并付加油费用 A。
3:在需要时可在网格点处增设油库,并付增设油库费用 C(不含加油费用A )。
4:汽车只能沿网格边行驶,装满油后能行驶 K 条网格边。
思路:这题是洛谷网络流24题里的,但是题解都是清一色的最短路哈哈。建图跑最短路。根据费用分层,因为装满油只能走k次,所以我们分为k+1层,第0层代表满油,第一层代表消耗了一单位油。
对于第一个条件:我们在这层连一条有向边到上一层跟他相邻的四个方向,如果x或者y坐标减少,边权为b,否则边权为0。
对于第二个条件:因为遇到油库就强制必须加油,所以,对于第一层及其以上的层连接一条边到第一层,边权为A,此时还需要连接第0层与第一层,但是不要连接其他层,这是因为,如果经过这个点,他下一步只可能是第一层,不可能是其他层。
对于第三个条件:如果这个点不是油库,每一层都连一条边到第一层,边权为a+c,代表在这个点新建了一个油库。
第四个条件:建分层图
#include <bits/stdc++.h>
#define ll long long
#define pi pair<int,int>
#define mk make_pair
#define pb push_back
using namespace std;
const int maxn = 1e6+10;
int d[maxn],vis[maxn],n;
vector<pi>G[maxn];
int id(int x,int y,int k)
{
return n*n*k + ((x-1)*n) + y;
}
void add(int u,int v,int w)
{
G[u].pb(mk(v,w));
}
void dij(int s)
{
priority_queue<pi>q;
memset(d,0x3f,sizeof(d));
d[s] = 0;
q.push(mk(0,s));
while(q.size())
{
int u = q.top().second;
q.pop();
if(vis[u])continue;
vis[u] = 1;
for(int i=0;i<G[u].size();i++)
{
int v = G[u][i].first;
int w = G[u][i].second;
if(d[v] > d[u] + w)
{
d[v] = d[u] + w;
q.push(mk(-d[v],v));
}
}
}
}
int main()
{
int k,a,b,c;
scanf("%d%d%d%d%d",&n,&k,&a,&b,&c);
for(int x=1;x<=n;x++)
for(int y=1;y<=n;y++)
{
int ddd;
scanf("%d",&ddd);
if(ddd == 1)
{
for(int i=1;i<=k;i++) {
add(id(x,y,i) , id(x,y,0) , a);
}
if(x+1 <= n) add(id(x, y, 0), id(x+1, y, 1), 0);
if(x-1 >= 1) add(id(x, y, 0), id(x-1, y, 1), b);
if(y+1 <= n) add(id(x, y, 0), id(x, y+1, 1), 0);
if(y-1 >= 1) add(id(x, y, 0), id(x, y-1, 1), b);
}
else
{
for(int i=1;i<=k;i++)
{
add(id(x,y,k), id(x,y,0), a+c);
if(x+1 <= n) add(id(x, y, i-1), id(x+1, y, i), 0);
if(x-1 >= 1) add(id(x, y, i-1), id(x-1, y, i), b);
if(y+1 <= n) add(id(x, y, i-1), id(x, y+1, i), 0);
if(y-1 >= 1) add(id(x, y, i-1), id(x, y-1, i), b);
}
}
}
int s = id(1,1,0);
dij(s);
int ans = 0x3f3f3f3f;
for(int i=0;i<=k;i++)ans = min(ans , d[id(n,n,i)]);
printf("%d\n",ans);
return 0;
}