网络流24题(十五)
网络流24题
十五、汽车加油行驶问题
题目描述
给定一个 \(N×N\) 的方形网格,设其左上角为起点\(◎\),坐标\((1,1)\),\(X\) 轴向右为正, \(Y\) 轴向下为正,每个方格边长为 \(1\) ,如图所示。
一辆汽车从起点\(◎\)出发驶向右下角终点\(▲\),其坐标为 \((N,N)\)。
在若干个网格交叉点处,设置了油库,可供汽车在行驶途中加油。汽车在行驶过程中应遵守如下规则:
-
汽车只能沿网格边行驶,装满油后能行驶 \(K\) 条网格边。出发时汽车已装满油,在起点与终点处不设油库。
-
汽车经过一条网格边时,若其 \(X\) 坐标或 \(Y\) 坐标减小,则应付费用 \(B\) ,否则免付费用。
-
汽车在行驶过程中遇油库则应加满油并付加油费用 \(A\)。
-
在需要时可在网格点处增设油库,并付增设油库费用 \(C\)(不含加油费用\(A\) )。
-
\(N,K,A,B,C\) 均为正整数, 且满足约束: \(2\leq N\leq 100,2 \leq K \leq10\)。
设计一个算法,求出汽车从起点出发到达终点所付的最小费用。
输入格式
文件的第一行是 \(N,K,A,B,C\) 的值。
第二行起是一个\(N\times N\) 的 \(0−1\) 方阵,每行 \(N\) 个值,至 \(N+1\) 行结束。
方阵的第 \(i\) 行第 \(j\) 列处的值为 \(1\) 表示在网格交叉点 \((i,j)\) 处设置了一个油库,为 \(0\) 时表示未设油库。各行相邻两个数以空格分隔。
输出格式
程序运行结束时,输出最小费用。
题解
模型
所谓网络流24题就是24道不需要网络流做的题。
这又是一道最短路。
考虑油量分层,层数即为消耗油量。
\(dis[now][i][j]\)表示第\(now\)层,位置是\(i,j\)的最短路径。
建边就是
当\(now\) == \(K\)时需要建立油库,相当于从\(dis[k][i][j]\)给\(dis[0][i][j]\)连接一条权值为\(a+c\)的边。
当此处有加油站的时候会被强制收费,只要\(now>0\)。就连边权\(a\)的边。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
int dis[110][110][15],init[110][110][15];
int n,k,a,b,c,ma[110][110];
struct node
{
int x,y,k;
};
queue<node> q;
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
int main()
{
scanf("%d%d%d%d%d",&n,&k,&a,&b,&c);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j) scanf("%d",&ma[i][j]);
memset(dis,20,sizeof(dis));
dis[1][1][k]=0;init[1][1][k]=1;
q.push((node){1,1,k});
while(!q.empty())
{
int X=q.front().x;
int Y=q.front().y;
int K=q.front().k;q.pop();
// cout<<"("<<X<<","<<Y<<")"<<" :"<<K<<" "<<dis[X][Y][K]<<endl;
init[X][Y][K]=0;
if(ma[X][Y]&&K!=k)//加油
{
if(dis[X][Y][k]>dis[X][Y][K]+a)
{
dis[X][Y][k]=dis[X][Y][K]+a;
if(!init[X][Y][k])
init[X][Y][k]=1,q.push((node){X,Y,k});
}
continue;
}
else
{
if(dis[X][Y][k]>dis[X][Y][K]+a+c)
{
dis[X][Y][k]=dis[X][Y][K]+a+c;
if(!init[X][Y][k])
init[X][Y][k]=1,q.push((node){X,Y,k});
}
}
if(K>0)//开车
for(int i=0;i<4;++i)
{
int x=X+dx[i];
int y=Y+dy[i];
if(x<1||x>n||y<1||y>n) continue;
int len=0;
if(x<X||y<Y) len=b;
if(dis[x][y][K-1]>dis[X][Y][K]+len)
{
dis[x][y][K-1]=dis[X][Y][K]+len;
if(!init[x][y][K-1])
init[x][y][K-1]=1,q.push((node){x,y,K-1});
}
}
}
int ans=(1<<30);
for(int i=0;i<=k;++i)
ans=min(ans,dis[n][n][i]);
printf("%d\n",ans);
return 0;
}