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

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.问题描述 给定一个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均为正整数。 算法设计: 求汽车从起出发到达终的一条所付费用最少的行驶路线。 数据输入: 输入数据。第一行是N,K,A,B,C的值,2 <= N <= 100, 2 <= K <= 10。第二行起是一个N*N 的0-1方阵,每行N 个值,至N+1行结束。方阵的第i 行第j 列处的值为1 表示在网格交叉(i,j)处设置了一个油库,为0 时表示未设油库。 各行相邻的2 个数以空格分隔。 结果输出: 将找到的最优行驶路线所需的费用,即最小费用输出. 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
  分析:根据题目的意思,要使汽车加油次数最少,就必须让汽车跑的尽可能远,直到无法到达下一站的时候才加油。   设汽车加满油后最多能行驶nkm,旅途中有k个加油站,D={d1,d2,d3,d4,...dk,d(k+1)}为相邻两个加油站之间的距离的集合,d1为从出发到第一个加油站之间的距离,d(k+1)为第k个加油站距离第k+1个加油站之间的距离。   贪心选择性质:设S={s1,s2,s3,...sn}为给汽车加过油的加油站的集合,易知有n个加油站汽车加过油,假设S为最有解,则n为最优值n(n<=k)。   设有d1+d2+....+d(m)<=n,d1+d2+...+d(m+1)>n,则为了得到最优解,第一次给汽车加油加油站为d(m)。若s1=d(m),则S就是一个以贪心选择开始的最优解。若汽车在第m个加油站之前已经加过油,则设S’=S-{s1}Ud(m),汽车在s1加满油后可到达s2,则在第m个加油站加满油后,汽车也毫无疑问能到达s2。也就是说S’是以贪心选择加油站dm开始的最优加油选择。由此可见,总存在以贪心选择开始的最优加油方案。   最优子结构:在做了贪心选择之后,原问题就变成了在第m个加油站到第k个加油站之间汽车加油的最少次数问题。假设能在第m个加油站到第k个加油站加更少次数的油,那么总的加油次数将小于n这与S为问题最优解相矛盾,所以每一步所做的贪心选择都将问题简化为一个更小的与原问题具有相同形式的子问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值