1003 Emergency (25 分)

  1. 原本想dijkstra算出最小的距离后,然后bfs+剪枝去找出所有满足条件的路径,时间卡的有点紧,过前三个点,相关的bfs的代码以 “// 没有用到,// 结束没有用到框出”,实际最后没用到

  2. 对dijkstra算法进行改进:

    1. dijkstra更新最短路径的过程中需要更新num[]数组(num[i]代表从开始点到点i已经累计的救援队的数量)和cnt[](cnt[i]代表从开始点到点i已经累计的路线的数量)数组,需要维护这两个数组,对于这两个数组的维护和对dijkstra的修改,需要注意的细节很多,在这里需要注意

      • 对于vis[i]数组的使用,需要注意:

      • // 下面的这句话不能写,即使是下面的循环for(int i=0;i<n;i++)写成for(int i=0;i<n-1;i++)也不行,因为这样会使得num和cnt数组没有维护好
        // vis[beg_]=true;
        cnt[beg_]=1;
        num[beg_]=vs[beg_];
        
        // 这么写会导致num[]和cnt[]数组没有更新好
        
      • // 这里更新一个dist[j]不要维护vis[]数组,因为如果维护了这个vis数组,下面的else中更新路径的选项就永远不会进入
        // 注意这里的num和cnt的维护
        
        for(int j=0;j<n;j++){
             // 没写!vis[j]因为需要持续更新num[]和cnt[]
             if(g[min_pos][j]+min_val<dist[j]){
                 dist[j]=g[min_pos][j]+min_val;
                 num[j]=num[min_pos]+vs[j];
                 // 这里容易写错,原本写的cnt[j]=1
                 cnt[j]=cnt[min_pos];
                 // vis[j]=true;
             }
             else if(g[min_pos][j]+min_val==dist[j]){
                 num[j]=max(num[min_pos]+vs[j],num[j]);
                 cnt[j]+=cnt[min_pos];
             }
        
      • // 没直接返回是为了持续更新上面的cnt和num数组
        // if(vis[end_]){
        //     return dist[end_];
        // }
        
        // 为了维护好cnt和num,同样的,这里不要直接返回
        
  3. 原解答

  4. 使用vector的一种解法

#include<cstdio>
#include<iostream>
#include <algorithm>
#include<vector>
#include <queue>
using namespace std;
const int MAXN=505;
const int INF=0x3f3f3f3f;

int vs[MAXN];	// 点的权值
int g[MAXN][MAXN];	// 存放图数据的矩阵,不可达为INF
int routes=0;	// 存放最终beg_到end_的发现的路线的数量
int max_people=0;	// 存放最终beg_到end_的最多聚集的救援队的数量
int cnt[MAXN];	// 起点到其它城市的路径的数量
int num[MAXN];	// 起点到其它城市的获得的救援队的数量

int dijkstra(int beg_,int end_, int n, int m){
    bool vis[MAXN]={false};	// 代表顶点i是否被浏览过
    int dist[MAXN]={0};	
    for(int i=0;i<n;i++){
        dist[i]=g[beg_][i];
    }
    dist[beg_]=0;
    // 下面的这句话不能写,即使是下面的循环for(int i=0;i<n;i++)写成for(int i=0;i<n-1;i++)也不行,因为这样会使得num和cnt数组没有维护好
    // vis[beg_]=true;
    cnt[beg_]=1;
    num[beg_]=vs[beg_];


    for(int i=0;i<n;i++){
        // 先找到最短的距离
        int min_val=INF,min_pos=-1;
        for(int j=0;j<n;j++){
            if(!vis[j]&&min_val>=dist[j]){
                min_val=dist[j];
                min_pos=j;
            }
        }
        if(min_pos==-1){
            return INF;
        }
        vis[min_pos]=true;
        for(int j=0;j<n;j++){
            // 没写!vis[j]因为需要持续更新num[]和cnt[]
            if(g[min_pos][j]+min_val<dist[j]){
                dist[j]=g[min_pos][j]+min_val;
                num[j]=num[min_pos]+vs[j];
                // 这里容易写错,原本写的cnt[j]=1
                cnt[j]=cnt[min_pos];
                // vis[j]=true;
            }
            else if(g[min_pos][j]+min_val==dist[j]){
                num[j]=max(num[min_pos]+vs[j],num[j]);
                cnt[j]+=cnt[min_pos];
            }

        }
        // 没直接返回是为了持续更新上面的cnt和num数组
        // if(vis[end_]){
        //     return dist[end_];
        // }

    }
    routes=cnt[end_];
    max_people=num[end_];
    return dist[end_];
}


// 没有用到
struct Node{
    int first;
    int second;
    int third;
    Node(){}
    Node(int first_,int second_,int third_){
        this->first=first_;
        this->second=second_;
        this->third=third_;
    }
};
queue<Node>q;
void bfs(int beg_,int end_,int n,int m,int short_dis){
    q.push(Node(beg_,0, vs[beg_]));
    while(!q.empty()){
        Node top=q.front();
        q.pop();
        int cost_already=top.second;
        int cur_place=top.first;
        int people_already=top.third;
        if(cur_place==end_&&cost_already==short_dis){
            routes++;
            if(max_people<people_already){
                max_people=people_already;
            }
        }
        for(int i=0;i<n;i++){
            Node node;
            if(cost_already+g[cur_place][i]<=short_dis){
                node.second=cost_already+g[cur_place][i];
                node.first=i;
                node.third=people_already+vs[i];
                q.push(node);
            }
        }
    }
    return;
}
// 结束没有用到

int main(){
    int n,m;
    int beg_,end_;
    scanf("%d%d%d%d",&n,&m,&beg_,&end_);
    int tmp;
    for(int i=0;i<n;i++){
        scanf("%d",&tmp);
        vs[i]=tmp;
    }

    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            g[i][j]=INF;
        }
    }
    int u,v,w;
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&u,&v,&w);
        g[u][v]=g[v][u]=w;
        // 没有对边进行去重
    }
//    if(n==0){
//        printf("%d %d\n",0,0);
//        return 0;
//    }
//    else if(beg_==end_){
//        printf("%d %d\n",1,vs[beg_]);
//        return 0;
//    }

    int short_dis=dijkstra(beg_,end_,n,m);
//    cout<<"short_dis: "<< short_dis<<endl;
//    bfs(beg_,end_,n,m,short_dis);
    printf("%d %d\n",routes,max_people);
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值