问题描述
给定一个 N*N的方形网格,设其左上角为起点◎,坐标为( 1,1),X轴向右为正, Y轴向下为正,每个方格边长为 1,如图所示。一辆汽车从起点◎出发驶向右下角终点▲,其坐标为( N,N)。在若干个网格交叉点处,设置了油库,可供汽车在行驶途中加油。汽车在行驶过程中应遵守如下规则:
(1)汽车只能沿网格边行驶,装满油后能行驶 K条网格边。出发时汽车已装满油,在起点与终点处不设油库。
(2)汽车经过一条网格边时,若其 X坐标或 Y坐标减小,则应付费用 B,否则免付费用。
(3)汽车在行驶过程中遇油库则应加满油并付加油费用 A。
(4)在需要时可在网格点处增设油库,并付增设油库费用 C(不含加油费用 A)。
(5)(1)~(4)中的各数 N、K、A、B、C均为正整数,且满足约束:2 ≤ N ≤ 100,2 ≤ K ≤ 10。设计一个算法,求出汽车从起点出发到达终点的一条所付费用最少的行驶路线。
数据输入:
文件的第一行是 N,K,A,B,C的值。第二行起是一个 N*N的 0-1方阵,每行 N个值,至 N+1行结束。方阵的第 i行第 j列处的值为 1表示在网格交叉点( i,j)处设置了一个油库,为 0时表示未设油库。各行相邻两个数以空格分隔。
分析:
f(x,y,0)表示从(1,1)到(x,y)所需最少费用。
f(x,y,1)表示从汽车行驶到(x,y)还能行驶的网格边数。
最终即求f[N][N][0]
递归表达式及主要思路:
1.比如现在到了(x,y),上个位置有4种可能abcd(不过考虑越界的情况,有时候小于4),这四个位置都对应一个费用。
2.比如先选择上个位置是a,现在再去考虑当前位置(到油站否,有没有有油),并加上相应的价格。
3.这是我们会得到一个(x,y)处的费用=a位置费用+当前位置的费用。
4.我们遍历4个位置,寻找到(x,y)处的最小费用即可。
f(1,1,0)=0 f(1,1,1)=k 初始
f(x,y,0)=min{f(x+s[i][0],y+s[i][1],0)+s[i][2]} (1<=i<=4) 从上个位置到达(x,y),"上个位置"有四种情况。
f(x,y,1)=f(x+s[j][0],y+s[j][1],1)-1
f(x,y,0)=f(x,y,0)+A f(x,y,1)=k (x,y)是油库
f(x,y,0)=f(x,y,0)+C+A f(x,y,1)=k (x,y)是不是油库,但是此时没有油了f(x,y,1)=0
其中s数组表示的四个方向的走向
s={{1,0,0},{0,1,0},{1,0,B},{0,1,B}}
完整代码传送门:
#include <iostream>
#define INF 100000;
using namespace std;
int main()
{
int N,K,A,B,C;
cin>>N>>K>>A>>B>>C;
int a[N+1][N+1];//N*N的那个网格
for(int i=1;i<=N;++i)
for(int j=1;j<=N;++j)
cin>>a[i][j];
int f[N+1][N+1][3];
for(int i=1;i<=N;++i)
for(int j=1;j<=N;++j)
{f[i][j][0]=INF;f[i][j][1]=K;}//初始化
int s[4][3]={{-1,0,0},{0,-1,0},{1,0,B},{0,1,B}};//4个方向,第三个参数是价格B
f[1][1][0]=0;f[1][1][1]=K;//起点值初始化
for(int x=1;x<=N;++x)
for(int y=1;y<=N;++y)
{
if(x==1&&y==1) continue;
int minmoney=INF;int minstep;//minmoney存储(x,y)上个位置的最小money
int tmpmoney,tmpstep;
for(int i=0;i<=3;++i)//遍历上一个位置的所有可能情况
{ if(x+s[i][0]<1||x+s[i][0]>N||y+s[i][1]<1||y+s[i][1]>N) continue;//超边界
tmpmoney=f[x+s[i][0]][y+s[i][1]][0]+s[i][2];
tmpstep=f[x+s[i][0]][y+s[i][1]][1]-1;
if(a[x][y]==1) {tmpmoney+=A;tmpstep=K;} //遇油站
if(a[x][y]==0&&tmpstep==0&&(x!=N||y!=N)) {tmpmoney+=A+C;tmpstep=K;}//没油了
if(minmoney>tmpmoney)//更新最小值 (最后储存上个位置中费用最少的)
{
minmoney=tmpmoney;
minstep=tmpstep;
}
}
if(f[x][y][0]>minmoney)//更新f
{
f[x][y][0]=minmoney;
f[x][y][1]=minstep;
}
}
cout<<endl;
for(int i=1;i<=N;++i)
{
for(int j=1;j<=N;++j)
cout<<f[i][j][0]<<' ';
cout<<endl;
}
return 0;
}