PAT.1003 Emergency - Dijikstra

PAT.1003 Emergency - Dijikstra

题目链接
还就那个很久没写算法题,今天开始刷一下PAT甲级题库,权当复健。

不想写Dijikstra

这样写的问题在于由于起点是不定的,按照路的顺序遍历可能导致当前两个点都不可达,因此在遍历到起点相关的路之前的路会全部作废,(而且忽略了双向的问题)

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

int cityCnt,roadCnt,start,des;
int minDis[505],minDisCnt[505],maxWeight[505],weights[505];

int main(){
    memset(minDis,0x3f3f3f3f,sizeof(minDis));
    cin>>cityCnt>>roadCnt>>start>>des;
    for(int i = 0 ; i < cityCnt ; ++i){
        cin>>weights[i];
        maxWeight[i] = weights[i];
    }
    minDis[start] = 0;
    for(int i = 0 ; i < roadCnt ; ++i){
        int ts,td,tl;
        cin>>ts>>td>>tl;
        if(minDis[ts] + tl < minDis[td]){
            minDisCnt[td] = 0;
            minDis[td] = minDis[ts] + tl;
            maxWeight[td] = maxWeight[ts] + weights[td];
        }else if(minDis[ts] + tl == minDis[td]){
            minDisCnt[td]++;
            maxWeight[td] = max(maxWeight[td],maxWeight[ts] + weights[td]);
        }
    }
    cout<<minDisCnt[des]+1<<' '<<maxWeight[des];
}

乖乖写

用小顶堆做优化。虽然因为这道题要统计最短路的最大人数,小顶堆也没好多少,但顺手还是这么写了。
用结构体来表示城市,两个属性(编号,到起点的(最小)距离)。
需要注意的地方是:

  • 当 当前节点距起点距离 + 路径长度 == 目标节点距起点距离的情况,显然出现这种情况时,目标节点已经到达过了,所以只需要更新最大人数,而不需要判断是否到达,也无需再加入优先队列。
  • 更新目标节点的最大人数时,应当根据当前节点的最大人数来更新。
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

int cityCnt,roadCnt,start,des;
//要维护所有的双向路,以及每个城市可达的城市,每个城市的权重,以及最短重复的次数
int paths[505][505],vis[505],weights[505],minDisCnt[505],minDis[505],maxWeights[505];
vector<int> neighbors[505];

struct node{
    int city;
    //当前城市到起点的距离
    int disFromStart;
    bool operator < (const node &a) const{
        return disFromStart > a.disFromStart;
    }
    node(int city, int disFromStart){
        this->city = city;
        this->disFromStart = disFromStart;
    }
};

int main(){
    cin>>cityCnt>>roadCnt>>start>>des;
    for(int i = 0 ; i < cityCnt ; ++i){
        cin>>weights[i];
    }
    for(int i = 0 ; i < roadCnt ; ++i){
        int ts,td,tl;
        cin>>ts>>td>>tl;
        paths[ts][td] = paths[td][ts] = tl;
        neighbors[ts].push_back(td);
        neighbors[td].push_back(ts);
    }
    memset(minDis,0x3f3f3f3f,sizeof(minDis));
    maxWeights[start] = weights[start];
    minDisCnt[start] = 1;
    priority_queue<node> reachableCity;
    reachableCity.push(node(start,0));
    while(!reachableCity.empty()){
        node currentNode = reachableCity.top();
        int currentCity = currentNode.city;
        int currentDis = currentNode.disFromStart;
        reachableCity.pop();
        if(vis[currentCity] != 0) continue;
        vis[currentCity] = 1;
        //检查当前节点的可达节点
        for(int desCity : neighbors[currentCity]){
            int desPathDis = paths[currentCity][desCity];
            int desDisFromStart = desPathDis + currentDis;
            if(vis[desCity] == 0 && desDisFromStart < minDis[desCity]){
                minDisCnt[desCity] = minDisCnt[currentCity];
                minDis[desCity] = desDisFromStart;
                maxWeights[desCity] = maxWeights[currentCity] + weights[desCity];
                reachableCity.push(node(desCity,desDisFromStart));
            }else if(desDisFromStart == minDis[desCity]){
                minDisCnt[desCity] += minDisCnt[currentCity];
                maxWeights[desCity] = max(maxWeights[desCity],maxWeights[currentCity] + weights[desCity]);
            }
        }
    }
    cout<<minDisCnt[des]<<' '<<maxWeights[des];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值