c++ 汽车加油行驶问题

汽车加油行驶问题

题目描述

给定一个 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 时表示未设油库。各行相邻两个数以空格分隔。

输出

将最小费用输出。

样例输入

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  

样例输出

12

提示

(none)

AC代码

#include <iostream> 
#include <string.h> 
using namespace std;
int n,k,a,b,c;
int g[101][101];
struct Point
{
    int x,y,o,ans;
};
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
int dm[4] = {0,1,0,1};//dm是控制回走的时候是否收费 
int f,e;
Point q[7000000],s;
bool used[101][101][11];
int m[101][101][11];
int main()
{
    cin >> n >>k >> a >>b >> c;//n是n行n列的矩阵 k是加满油后能行的路程 a是加油的费用
	//b是倒退的费用 c造加油站的费用 
    for (int i=1;i <= n;i++)//将矩阵转换为数组 
        for (int j = 1;j <= n;j++)
            scanf("%d",&g[i][j]);//输入 
    s.x= 1,s.y = 1,s.o = k,s.ans = 0;//s.x是起点的x坐标 s.y是起点的y坐标 
	//s.o就是汽车可以行驶的剩余路程  s.ans是从起点到此地的钱数 
	memset(used,0,sizeof(used));//memset()把used[][][]全部初始化为0     
	used[1][1][k] = 1;//把起点标为已经走过,(并记录剩余的路程为k)     
	m[1][1][k] = 0;//走到这里时一共用的钱数 (并记录剩余的路程为k)  
	f=1,e=1;//f出队 e入队 
	q[1]=s;//把s入队     
	while (f <= e)//防止越界     
	{
        Point u = q[f++];//u是选中的元素         
		for (int i = 0;i < 4;i ++)//重复向4个方向拓展         
		{
            Point v = u;//v是由u拓展而来             
			v.x = u.x + dx[i];//向4个方向拓展  
			v.y = u.y + dy[i];//up
            v.o = u.o - 1;//剩余路程 -1 
			v.ans = u.ans + dm[i] * b;//v.ans是钱数  u.ans + dm[i] * b  是 加上回走的费用
			//dm[i]是1  , 表示回走 dm[i]是0 表示不回走  
			if (v.x < 1 || v.x > n || v.y < 1 || v.y > n) continue;//保证这些拓展而来的坐标在棋盘上             
			if (v.o < 0) continue;//剩余路程 > 0才可以继续行驶             
			if (g[v.x][v.y] == 1) //如果是加油站 就要加油 
			{ 
                v.ans += a;//加上加油费 
				v.o = k;//重新计算可行驶的路程 
				if (used[v.x][v.y][v.o] == 0 || (used[v.x][v.y][v.o] == 1 && v.ans < m[v.x][v.y][v.o]))
                {
                    used[v.x][v.y][v.o] = 1;//把这个点标为走过 
                    m[v.x][v.y][v.o] = v.ans;//把现在的钱数赋值(弄)到总钱数里面 
                    //m[][][]是存储所有点的钱数的数组 
                    //是否可以不用数组的方式,用一个变量每次比较并覆盖 
                    e ++;//e是入队下标 
                    q[e] = v;//把v入队 
                }
            }
            if (g[v.x][v.y]==0) //如果不是加油站 
            { 
                if(v.o>=0)//还可以开(还有油) 
                {
                    if (used[v.x][v.y][v.o] == 0 || (used[v.x][v.y][v.o] == 1 && v.ans < m[v.x][v.y][v.o]))
                    {
                        used[v.x][v.y][v.o] = 1;//已使用 
                        m[v.x][v.y][v.o] = v.ans;//把现在的钱数赋值(弄)到总钱数里面 
                        e ++;//e是入队下标 
                        q[e] = v;//把v入队 
                    }  
                }
                v.ans+=a+c,v.o=k;//造加油站  付钱    重新计算可行驶的路程  
                if (used[v.x][v.y][v.o] == 0 || (used[v.x][v.y][v.o] == 1 && v.ans < m[v.x][v.y][v.o]))
                {
                    used[v.x][v.y][v.o] = 1;//已使用 
                    m[v.x][v.y][v.o] = v.ans;
                    e ++;
                    q[e] = v;
                }
            }
        }
    }    
    int res = 1000000000;//把res设成最大,取最小值 
    for (int i = 0;i <= k ;i++)//重复计算 
        if (res > m[n][n][i] && m[n][n][i] != 0) res = m[n][n][i];//取最小值 
    cout << res << endl;//将最后一个点的费用输出(即最小费用) 
    return 0;
}

(未完待续)

原文地址:https://www.cnblogs.com/LJA001162/p/11299957.html