5.14每日一题题解

紧急救援

涉及知识点:

  • Dijkstra/DFS

solution:

  • \(这个题有两种做法第一种是Dijkstra + DFS\)
  • \(这个做法呢,这个解法是:我们把所有的最短路求出来,然后再根据救援人数最多进行深搜,回溯\)
  • \(另一个是 Dijkstra + 记录\)
  • \(代码我已经把重要的难以理解的地方加上了注释\)
  • \(由于N的范围是500,那么我们可以判定这个图为稠密图,需要用邻接矩阵来存,当然如果用邻接表来存的话,那就需要用对优化的Dijkstra\)
  • \(最好是用邻接表来存\)
  • \(如果t这个点可以更新v这个点,那么到达v的路径,就应该和到达t的路径一样,人数就应该是到达t的总人数加上在v的总人数\)
  • \(并且v的前驱就是t,pre[v] = t\)
  • \(如果此时t到v的距离和原点到达v的距离相等,那么在v的路径总数应该是nums[v]+=nums[t]\)
  • \(如果人数可以更新的话,那么我们就更新一下总人数,pre[v] = t,w[v] = w[t] + weights[v]\)

std:


#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 510;
int n,m;
int dist[N];
bool st[N];
int weights[N];
int g[N][N];
int w[N];
int start,en;

vector<int>pre[N];// 记录所有的最短路径是怎么走的

void Dijkstra()
{
    memset(dist,0x3f,sizeof dist);

    dist[start] = 0;

    for(int i = 0;i < n;i++)
    {
        int t = -1;

        for(int j = 0;j < n;j++)
        {
            if(!st[j]&&(t==-1||dist[t]>dist[j]))t = j;
        }
        if(t==-1)return;
        st[t] = true;
        for(int v = 0;v < n;v++)
        {
            // 如果当前这个点t可以更新v这个点,那么,v的前驱就是t,由于v之前可能有别的前驱,所以我们需要把pre[v],清空
            if(dist[v] > dist[t] + g[t][v])
            {
                dist[v] = dist[t] + g[t][v];
                pre[v].clear();
                pre[v].push_back(t);

            } // t为v的前驱之一
            else if(dist[v] == dist[t] + g[t][v])
            {
                pre[v].push_back(t);
            }
        }
    }
}
vector<int>path;//记录答案
vector<int>tempPath;// 记录临时答案
int val = 0;// 记录最大人数
int cnt = 0;// 记录最短路的条数

void dfs(int v)
{
    tempPath.push_back(v);// 把当前点放到vector里面
    if(v == start)
    {
        cnt++;
        int value = 0;
        for(auto &x : tempPath)
        {
            value += weights[x];
        }

        if(value > val)
        {
            val = value;
            path = tempPath;
        }
        tempPath.pop_back();
        return;
    }
    
    for(auto &x : pre[v])
    {
        dfs(x);
    }
    
    tempPath.pop_back();//回溯
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m >> start >> en;
    memset(g,0x3f,sizeof g);
    for(int i = 0;i < n;i++)
    {
        cin >> weights[i];
    }
    for(int i = 0;i < m;i++)
    {
        int a,b,c;
        cin >> a >> b >> c;
        g[a][b] = g[b][a] = min(g[a][b],c);
    }
    Dijkstra();
    for(auto &x : pre[en])
    {
        dfs(x);
    }
    cout << cnt <<" " << val + weights[en] << endl;
    int size = path.size();
    for(int i = size - 1;~i;i--)
    {
        cout << path[i] << " ";
    }
    cout << en;
    return 0;
}
// 第二种做法
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 510;
int n,m;
int dist[N];
int pre[N];
bool st[N];
int nums[N];
int weights[N];
int g[N][N];
int w[N];
int start,en;

void Dijkstra()
{
    memset(dist,0x3f,sizeof dist);

    dist[start] = 0;

    w[start] = weights[start];

    for(int i = 0;i <= n;i++)
    {
        pre[i] = i;
    }

    nums[start] = 1;

    for(int i = 0;i < n;i++)
    {
        int t = -1;

        for(int j = 0;j < n;j++)
        {
            if(!st[j]&&(t==-1||dist[t]>dist[j]))t = j;
        }
        
        
        if(t==-1)return;

        st[t] = true;

        for(int v = 0;v < n;v++)
        {
            if(dist[v] > dist[t] + g[t][v])
            {
                dist[v] = dist[t] + g[t][v];

                nums[v] = nums[t];

                w[v] = w[t] + weights[v];

                pre[v] = t;
            }
            else if(dist[v] == dist[t] + g[t][v])
            {
                nums[v] = nums[t] + nums[v];

                if(w[t] + weights[v] > w[v])
                {
                    pre[v] = t;
                    w[v] = w[t] + weights[v];
                }
            }
        }
    }

}

vector<int>road;

void dfs(int e)
{
    if(e==start){
        road.push_back(e);return ;
    }
    dfs(pre[e]);
    road.push_back(e);
}

int main()
{
    
    ios::sync_with_stdio(false);
    
    cin >> n >> m >> start >> en;

    memset(g,0x3f,sizeof g);

    for(int i = 0;i < n;i++)
    {
        cin >> weights[i];
    }

    for(int i = 0;i < m;i++)
    {
        int a,b,c;
        cin >> a >> b >> c;
        g[a][b] = g[b][a] = min(g[a][b],c);
    }

    Dijkstra();

    cout << nums[en] << " " << w[en] << endl;

    bool tf = false;

    dfs(en);

    for(auto &x : road)
    {
        if(tf)cout << " ";
        cout << x;
        tf = true;
    }

    return 0;
}
posted @ 2020-05-14 11:11  QFNU-ACM  阅读(114)  评论(0编辑  收藏  举报