poj3635题解

//Memory 15984K Time 891MS
#include <iostream>
#include <cstdio>
#include <list>
#include <queue>

using namespace std;

int cityNum;//城市数量
int roadNum;//城市之间的道路数量

//到达顶点v需要消耗的汽油oil
struct ArriveGoalNode {
    int v, oil;
};

//ver[currarriveGoalNode.u].arcs.begin()
//城市加油的结构体
struct VertexInfo {
    int oilCost;//在当前城市加油需要的费用
    //从当前城市出发到达另外的城市
    list<ArriveGoalNode> arcs;
} *verNum;//存储城市信息的一维数组

//汽车的当前状态
struct State {
    //汽车当前所在的城市
    int nowCity;
    //汽车当前加油
    //累加消耗的费用
    int cost;
    //汽车当前的剩余汽油量
    int restOil;


    //重载小于运算符
    //使汽车的状态结构体对象
    //能够调整优先级
    //使当前汽车累加消耗的最少费用节点
    //处在优先队列的对首
    bool operator<(const State &obj) const {
        return cost > obj.cost;
    }
};


//构造从a城市到达b城市,并且需要消耗oil油量的边
void createEdge(int a, int b, int oil) {
    ArriveGoalNode arc;
    arc.v = b;
    arc.oil = oil;
    //从城市a出发到达城市b
    //将城市b节点加到城市a对应的arcs
    verNum[a].arcs.push_back(arc);
}

//bfs(maxCapacity, s, e, ans)
void bfs(int capacity, int beginCity, int endCity, int &optimal) {
    priority_queue<State> pq;
    //isVisit[i][j]到达加油站i,油箱剩余油量为j
    //当前累加加油费用
    //初始化记录数组
    int **isVisit = new int *[cityNum];
    for (int i = 0; i < cityNum; i++)
        isVisit[i] = new int[capacity + 1];

    //初始化每行的每一列
    for (int i = 0; i < cityNum; i++)
        fill(isVisit[i], isVisit[i] + capacity + 1, 1 << 20);

    //初始化汽车开始状态
    State beginState;
    beginState.nowCity = beginCity;
    beginState.restOil = 0;
    beginState.cost = 0;
    pq.push(beginState);
    isVisit[beginState.nowCity][beginState.restOil] = 0;

    //队列不为空
    while (!pq.empty()) {
        //取出对首数据
        State nowState = pq.top();
        pq.pop();

        //到达目标地点(到达叶子节点)
        if (nowState.nowCity == endCity) {
            //将当前已经累加的最少加油费用赋值给ans
            optimal = nowState.cost;
            return;
        }

        //加油过程
        //当前汽车的油量未达到油箱最大容量
        //并且汽车目前加油累加的消耗费用,加上在当前城市加油消耗的费用
        //小于在当前城市加了一个单位的油后的最小费用
        if (nowState.restOil < capacity &&
            nowState.cost + verNum[nowState.nowCity].oilCost < isVisit[nowState.nowCity][nowState.restOil + 1]) {
            State temPoraryState;
            temPoraryState.nowCity = nowState.nowCity;
            //在当前城市加一个单位的油
            temPoraryState.restOil = nowState.restOil + 1;
            //累加在当前城市加一个单位的油,的费用
            temPoraryState.cost = nowState.cost + verNum[nowState.nowCity].oilCost;
            pq.push(temPoraryState);
            isVisit[temPoraryState.nowCity][temPoraryState.restOil] = temPoraryState.cost;
        }

        //出发过程
        //遍历以当前城市为起点,可到达的城市
        for (list<ArriveGoalNode>::iterator it = verNum[nowState.nowCity].arcs.begin();
             it != verNum[nowState.nowCity].arcs.end(); it++)
            //当前汽车剩余油量大于从a顶点到达第一个与a相连的顶点之间的权值(即需要消耗的油量)
            //当前汽车已经累加的加油费用小于到达加油站v(在油量剩余为出发前的油量减去路途消耗的油量)的最小累加加油费用
            //即汽车可以从顶点u到达顶点v
            //并且可能找到更好的解

            //isVisit[i][j]到达加油站i,油箱剩余油量为j
            //当前累加加油费用
            if (nowState.restOil >= it->oil &&
                nowState.cost < isVisit[it->v][nowState.restOil - it->oil]) {
                State finalState;
                //更新节点信息
                finalState.nowCity = it->v;
                finalState.restOil = nowState.restOil - it->oil;
                finalState.cost = nowState.cost;
                pq.push(finalState);
                isVisit[finalState.nowCity][finalState.restOil] = finalState.cost;
            }

    }

    //释放内存
    for (int i = 0; i < cityNum; i++)
        delete[] isVisit[i];
    delete[] isVisit;
}

int main() {
    //录入城市数量和城市之间的道路数量
    while (~scanf("%d%d", &cityNum, &roadNum)) {

        //城市节点信息
        verNum = new VertexInfo[cityNum];
        for (int i = 0; i < cityNum; i++)
            //录入每个城市加油需要的费用
            scanf("%d", &verNum[i].oilCost);

        //录入城市之间的道路
        //(从a城市到达b城市需要消耗的油量为oil)
        for (int i = 0; i < roadNum; i++) {
            int a, b, oil;
            scanf("%d%d%d", &a, &b, &oil);
            //构造虚拟图中的a顶点到b顶点的边
            //边的权值对应a顶点到b顶点需要消耗的油量
            createEdge(a, b, oil);
            createEdge(b, a, oil);
        }

        //查询数量的录入
        int queryNum;
        scanf("%d", &queryNum);

        //录入具体的每条查询的信息
        //即汽车在油箱容量最大为maxCapacity
        //是否能从a城市到达b城市
        for (int i = 0; i < queryNum; i++) {

            int maxCapacity, beginCity, endCity;
            scanf("%d%d%d", &maxCapacity, &beginCity, &endCity);
            int optimal = 1 << 30;
            //ans存储汽车在maxCapacity的最大油箱容量
            //从a城市到达b城市,如果可行的最少加油费用
            bfs(maxCapacity, beginCity, endCity, optimal);
            optimal == 1 << 30 ? printf("impossible\n") : printf("%d\n", optimal);
        }
    }
    //释放内存
    delete[] verNum;
    return 0;
}

//简洁版
#include <iostream>
#include <cstdio>
#include <list>
#include <queue>

using namespace std;

struct ArriveGoalNode {
    int v;
    int oil;
};

struct VertexInfo {
    int oilCost;
    list<ArriveGoalNode> arcs;
};

struct State {
    int nowCity;
    int restOil;
    int cost;
    bool operator<(const State &obj) const {
        return cost > obj.cost;
    }
};

int cityNum;
int roadNum;
VertexInfo *verNum;

void createEdge(int a, int b, int oil) {
    ArriveGoalNode arc;
    arc.v = b;
    arc.oil = oil;
    verNum[a].arcs.push_back(arc);
}

void bfs(int capacity, int beginCity, int endCity, int &optimal) {
    priority_queue<State> pq;
    int **isVisit = new int *[cityNum];
    for (int i = 0; i < cityNum; i++)
        isVisit[i] = new int[capacity + 1];

    for (int i = 0; i < cityNum; i++)
        fill(isVisit[i], isVisit[i] + capacity + 1, 1 << 20);

    State beginState;
    beginState.nowCity = beginCity;
    beginState.restOil = 0;
    beginState.cost = 0;
    pq.push(beginState);
    isVisit[beginState.nowCity][beginState.restOil] = 0;

    while (!pq.empty()) {
        State nowState = pq.top();
        pq.pop();

        if (nowState.nowCity == endCity) {
            optimal = nowState.cost;
            return;
        }

        if (nowState.restOil < capacity &&
            nowState.cost + verNum[nowState.nowCity].oilCost < isVisit[nowState.nowCity][nowState.restOil + 1]) {
            State temPoraryState;
            temPoraryState.nowCity = nowState.nowCity;
            temPoraryState.restOil = nowState.restOil + 1;
            temPoraryState.cost = nowState.cost + verNum[nowState.nowCity].oilCost;
            pq.push(temPoraryState);
            isVisit[temPoraryState.nowCity][temPoraryState.restOil] = temPoraryState.cost;
        }

        for (auto it = verNum[nowState.nowCity].arcs.begin(); it != verNum[nowState.nowCity].arcs.end(); it++)
            if (nowState.restOil >= it->oil &&
                nowState.cost < isVisit[it->v][nowState.restOil - it->oil]) {
                State finalState;
                finalState.nowCity = it->v;
                finalState.restOil = nowState.restOil - it->oil;
                finalState.cost = nowState.cost;
                pq.push(finalState);
                isVisit[finalState.nowCity][finalState.restOil] = finalState.cost;
            }

    }

    for (int i = 0; i < cityNum; i++)
        delete[] isVisit[i];
    delete[] isVisit;
}

int main() {
    while (~scanf("%d%d", &cityNum, &roadNum)) {

        verNum = new VertexInfo[cityNum];
        for (int i = 0; i < cityNum; i++)
            scanf("%d", &verNum[i].oilCost);

        for (int i = 0; i < roadNum; i++) {
            int a, b, oil;
            scanf("%d%d%d", &a, &b, &oil);
            createEdge(a, b, oil);
            createEdge(b, a, oil);
        }

        int queryNum;
        scanf("%d", &queryNum);

        for (int i = 0; i < queryNum; i++) {

            int maxCapacity, beginCity, endCity;
            scanf("%d%d%d", &maxCapacity, &beginCity, &endCity);
            int optimal = 1 << 30;
            bfs(maxCapacity, beginCity, endCity, optimal);
            optimal == 1 << 30 ? printf("impossible\n") : printf("%d\n", optimal);
        }
    }
    delete[] verNum;
    return 0;
}

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值