7-35 城市间紧急救援 (25 分)

作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:
输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。

第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。

输出格式:
第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。

输入样例:
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2
输出样例:
2 60
0 1 3
题目来源:PTA数据结构与算法题目集(中文)
(算法小白,大佬绕道)

(朴素)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N = 510;

int g[N][N];//存图
int dist[N];//存距离
int pre[N];//标记前一个点在哪
int ansp[N];//最大救援数量
int people[N];//初始救援人员数量
int path[N];//记录路径
int rodenum[N];//快速通道数量
bool st[N];//记录每个点是否被遍历过
int n,m,s,d;

void disjkstra()
{
    memset(dist,0x3f,sizeof dist);
    memset(st,0,sizeof st);
    dist[s] = 0;
    ansp[s] = people[s];
    rodenum[s] = 1;
    for(int i = 0;i < n-1;i++)
    {
        int t = -1;
        for(int j = 0;j < n;j++)
        {
            if(!st[j] && (t ==-1 || dist[t] > dist[j]))
                t = j;
        }
        st[t] = true;
        for(int j = 0;j < n;j++)
        {
            if (dist[j] > dist[t] + g[t][j]) {
				dist[j] = dist[t] + g[t][j];
				rodenum[j] = rodenum[t];
				pre[j] = t;
				ansp[j] = ansp[t] + people[j];
			}
            else {
				if (dist[j] == dist[t] + g[t][j]) {
					rodenum[j] += rodenum[t];
					if (ansp[j] < people[j] + ansp[t]) {
						ansp[j] = people[j] + ansp[t];
						pre[j] = t;
					}
				}
			}
        }
    }
    cout << rodenum[d] << ' ' << ansp[d] <<endl;
        int x = d ;
        int h = 0 ;
        while(x != s)
        {
            path[h++] = x;
            x = pre[x];
        }
        cout<< s;
        for(int i = h-1;i >= 0;i--)
        {
            cout<<' '<<path[i];
        }
        cout<<endl;
}

int main()
{
    cin>>n>>m>>s>>d;
    memset(g,0x3f,sizeof g);
    for(int i = 0;i < n;i++)cin>>people[i];
    for(int i = 0;i < m;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        g[x][y] = g[y][x] = z;
    }
    dijkstra();
}

在这里插入图片描述(堆优化版)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std ;
typedef pair<int , int > PII ;
const int N = 510 , M = N*N;
int peopel[N] ;  
int st[N] ;   
int rodenum[N] ;  
int dist[N]  ;   
int n , m , sr , ed ;
int ansp[N] ; 
int h[N] , e[M] , ne[M] , idx , W[M]; 
int path[N];
int pre[N];

void add(int a , int b  ,int c ) 
{
    W[idx] = c , e[idx] = b , ne[idx] = h[a] , h[a] = idx++ ;
}

void dijkstra(int s )
{
    memset(dist,0x3f,sizeof dist) ;
    dist[s] = 0 ;
    rodenum[s] = 1 ;
    ansp[s] = peopel[s] ; 

    priority_queue<PII ,vector<PII> ,greater<PII>>  q ; // 小根堆
    q.push({0,s});
    while(q.size())
    {
        auto t = q.top() ;
        q.pop();
        int ver = t.second , dis = t.first ;  //        取出节点编号和节点距离 
        if(st[ver]) continue;
        st[ver] = 1 ;
        for(int i = h[ver] ;~i ; i= ne[i] )
        {
            int j = e[i] , k = W[i] ;

            if(dist[j] > dis + k )
            {
                dist[j] = dis + k;
                rodenum[j]= rodenum[ver] ;
                ansp[j] = ansp[ver] +  peopel[j] ; 
                pre[j] = ver;
                q.push({dist[j] , j }) ;
            }
            else 
            {
                if(dist[j] == dis + k ){
                    rodenum[j] += rodenum[ver] ;
                    if(ansp[j] < ansp[ver] +  peopel[j]){
                        ansp[j] = ansp[ver] +  peopel[j] ; 
                        pre[j] = ver;
                    }
                    
                }
            }
        }
    }
    cout << rodenum[ed] << " " << ansp[ed]<<endl ;
    cout<<sr;
    int x = ed,h = 0;
    while(x != sr)
    {
        path[h++] = x;
        x = pre[x];
    }
    for(int i = h-1; i >= 0;i--)
        cout<<' '<<path[i];
}
int main() 
{
    memset(h,  -1 , sizeof h ) ;
    cin >> n >> m >> sr >> ed ;
    for(int i = 0 ; i < n ; i ++ )
    {
        cin >> peopel[i] ;
    }
    for(int i = 0 ; i < m ; i ++ )
    {
        int a , b , w ;
        cin >> a >>b >> w ;
       add(a, b ,w) , add(b,a ,w) ;

    }
    dijkstra(sr) ;
    
    return 0 ;
}


在这里插入图片描述
至于disjkstra的选法:稠密图用朴素版、稀疏图用堆优化版即可,至于spfa,被卡就换disjkstra。
(spfa)

#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N = 1010,M = N*N;

int n,m,s,d;
int people[N];
int rodenum[N],ansp[N],dist[N];
int h[N],w[M],e[M],ne[M],idx;
int pre[N],path[N];
bool st[N];

void add(int a,int b,int c)
{
    w[idx] = c,e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

void spfa()
{
    memset(dist,0x3f,sizeof dist);
    memset(st,0,sizeof st);
    dist[s] = 0;
    rodenum[s] = 1;
    ansp[s] = people[s];

    queue<int>  q ; 
    q.push(s);
    st[s] = 1;
    
    while(q.size())
    {
        int t = q.front();
        q.pop();
        st[t] = 0;
        for(int i = h[t];i != -1;i=ne[i])
        {
            int j = e[i];
            if(dist[j] > dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                rodenum[j] = rodenum[t];
                ansp[j] = people[j] + ansp[t];
                pre[j] = t;
                if(!st[j])
                {
                    q.push(j);
                    st[j] = 1;
                }
            }
            else{
                if(dist[j] == dist[t] + w[i] ){
                    rodenum[j] += rodenum[t] ;
                    if(ansp[j] < ansp[t] +  people[j]){
                        ansp[j] = ansp[t] +  people[j] ; 
                        pre[j] = t;
                    }
                }
            }
            
        }
    }
    cout << rodenum[ed] << " " << ansp[ed]<<endl ;
    cout<<sr;
    int x = ed,h = 0;
    while(x != sr)
    {
        path[h++] = x;
        x = pre[x];
    }
    for(int i = h-1; i >= 0;i--)
        cout<<' '<<path[i];
}

int main()
{
    cin>>n>>m>>s>>d;
    memset(h,-1,sizeof h);
    for(int i = 0;i < n;i++)cin>>people[i];
    for(int i = 0;i < m;i++)
    {
        int a,b,w;
        cin>>a>>b>>w;
        add(a,b,w);
        add(b,a,w);
    }
    spfa();
    return 0;
}

分不全,还在找
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值