题目描述 Description
给定一个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。
设计一个算法,求出汽车从起点出发到达
输入描述 Input Description
第一行是N,K,A,B,C的值。第二行起是一
个N*N 的0-1 方阵,每行N 个值,至N+1 行结束。方阵的第i 行第j 列处的值为1 表示在
网格交叉点(i,j)处设置了一个油库,为0 时表示未设油库。各行相邻两个数以空格分隔。
输出描述 Output Description
程序运行结束时,将最小费用输出
样例输入 Sample Input
9 3 2 3 6
0 0 0 0 1 0 0 0 0
0 0 0 1 0 1 1 0 0
1 0 1 0 0 0 0 1 0
0 0 0 0 0 1 0 0 1
1 0 0 1 0 0 1 0 0
0 1 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0 1
1 0 0 1 0 0 0 1 0
0 1 0 0 0 0 0 0 0
样例输出 Sample Output
12
终点的一条所付费用最少的行驶路线。
解题思路:定义dp[i][j][2]数组,dp[i][j][0]代表从起点到(i,j)所花费的最小费用,dp[i][j][1]代表从起点到(i,j)还能行使的网格边数,于是有初始状态dp[1][1][0]=0,dp[1][1][1]=K。
其次有数组dir[4][3],dri[i][0]代表x方向,dir[i][1]代表y方向,dir[i][2]代表行使所花费的费用
对于任意一个点(i,j)能够到达它的点为上下左右四个点(i-1,j)(i+1,j) (i,j-1)(i,j+1)。
因此有状态转移方程为dp[i][j][0]=min(上下左右四个方向到达(i,j)的费用)
费用的计算细节详见代码
#include <iostream>
#include <string.h>
#define inf 0x3f3f3f3f
#define maxn 105
using namespace std;
int N,K,A,B,C;
//dp二维数组代表答案更新数组,grap代表所输入的二维矩阵
int dp[maxn][maxn][2],grap[maxn][maxn];
int main()
{
cin>>N>>K>>A>>B>>C;
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)cin>>grap[i][j];
//方向数组其中:dir[j][3]:j=0->3:分别代表左,上,右,下
//dir[j][0]为x坐标的增加情况,dir[j][1]为y坐标的增加情况
//dir[j][2]为是否需要增加费用 ,即是否进行了坐标减小的走法
int dir[4][3]={{0,-1,0},{-1,0,0},{0,1,B},{1,0,B}};
memset(dp,inf,sizeof(dp));//dp数组初始化为极大值
dp[1][1][0]=0;dp[1][1][1]=K;//初始化状态在(1,1)处花费应为0,还能走的步数为K
bool ok=true;//ok为true是代表还能进行更新
while(ok)
{
ok=false;
for(int i=1;i<=N;i++)
{
for(int j=1;j<=N;j++)
{
if(i+j==2)continue;//当为起点时略过
int now0=dp[i][j][0];//当前坐标的花费
int now1=dp[i][j][1];//当前坐标还能行走的步数
for(int k=0;k<4;k++)//考虑与当前坐标相邻的四个方向的状态,称做QD
{
int dx=i+dir[k][0];//QD的横坐标计算
int dy=j+dir[k][1];//QD的纵坐标计算
int db=dir[k][2];//从(dx,dy)到(i,j)是否需要额外增加费用,即从QD到现在是否需要额外费用
if(dx<1||dx>N||dy<1||dy>N)continue;//当在地图外时忽略该种状态
int newn0=dp[dx][dy][0]+db;//利用QD更新后的dp[i][j]的费用
int newn1=dp[dx][dy][1]-1;//利用QD更新后的dp[i][j]还能走的步数
if(grap[i][j])//当(i,j)为一个油库时,需要进行如下处理
{
newn0+=A;
newn1=K;
}
//当从QD到(i,j)后能走的步数为0时,我们需要在(i,j)处增设一个油库
//但(i,j)不能是终点(N,N),因为终点不能增设油库
if(newn1==0&&(i+j!=2*N))
{
newn0+=(A+C);
newn1=K;
}
//当更新后的状态优于更新前的状态执行本次更新
if(newn0<now0)
{
dp[i][j][0]=newn0;
dp[i][j][1]=newn1;
ok=true;
}
}
}
}
}
cout<<dp[N][N][0];
}
/*
//测试样例
9 3 2 3 6
0 0 0 0 1 0 0 0 0
0 0 0 1 0 1 1 0 0
1 0 1 0 0 0 0 1 0
0 0 0 0 0 1 0 0 1
1 0 0 1 0 0 1 0 0
0 1 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0 1
1 0 0 1 0 0 0 1 0
0 1 0 0 0 0 0 0 0
3 3 3 3 3
0 0 0
0 1 0
0 0 0
*/