1. 程式人生 > >PAT A1003 Emergency(25 分)----最短路徑

PAT A1003 Emergency(25 分)----最短路徑

總結:這道題坑的地方在於求最大集結救援隊是值得一條最短路線上的所有節點之和,而不是所有最短路徑上的節點之和

深搜(dfs):

1.求路徑,點權,邊權。遍歷,最大連通子圖。

2.兩段程式碼分別使用深搜和dijkstra演算法解決的,有興趣可以兩端都看看,第二段程式碼比第一段快,遞迴程式消耗大。

dijkstra演算法相當於非遞迴版的廣度搜索。

程式碼:

#include<iostream>
#include<vector>
#include<map>
#include<set>
using namespace std;
int G[600][600];       //邊權
int weight[600];       //點權
int vi[600];
int minlen = 999999;
int totalen = 0;
map<int,vector<vector<int>>> so;
int n, m, c1, c2;
void dfs(int index, vector<int> road)
{
    if (vi[index])return;
    if (index == c2)
    {
        if (totalen <= minlen){ minlen = totalen;  so[minlen].push_back(road); }
        return;
    }
    vi[index] = 1;
    for (int i = 0; i <n; i++)
    {
        if ((!vi[i]) && (G[index][i]))
        {
            if (totalen + G[index][i]>minlen)continue;
            totalen += G[index][i];
            road.push_back(i);
            dfs(i, road);
            totalen -= G[index][i];
            road.pop_back(); vi[i] = 0;
        }
    }
}
int main()
{
    cin >> n >> m >> c1 >> c2;
    for (int i = 0; i <n; i++)
    {
        int wt; scanf("%d", &wt);
        weight[i] = wt;
    }
    for (int i = 0; i < m; i++)
    {
        int a, b, ti;
        scanf("%d%d%d", &a, &b, &ti);
        G[a][b] = ti; G[b][a] = ti;
    }
    vector<int> road;
    road.push_back(c1);
    dfs(c1, road);
    int sum = 0; int total;
    for (int i = 0; i < so[minlen].size(); i++){
        total = 0;
        for (int j = 0; j < so[minlen][i].size(); j++)
        {
            total+=weight[so[minlen][i][j]];
        }
        if (total>sum)sum = total;
    }
    cout << so[minlen].size()<<" "<<sum;
    return 0;
}

程式碼2:

dijkstra演算法:

#include<iostream>
#include<vector>
#include<map>
#include<set>
using namespace std;
int G[600][600];       //邊權
int weight[600];       //點權
int num[600];       //最短路徑條數
int dis[600];         //起點到i的最短路徑
int w[600];              //路徑上的點權之和
int vi[600];              //訪問標誌
const int inf = 99999999;         
int main()
{
    int n, m, c1, c2;
    cin >> n >> m >> c1 >> c2;
    fill(G[0], G[0] + 600 * 600, inf);     //路徑設為inf=---不可到達
    for (int i = 0; i < n; i++)
        scanf("%d",&weight[i]);
    for (int i = 0; i < m; i++)
    {
        int a, b, ti;
        scanf("%d%d%d", &a, &b, &ti);
        G[a][b] = ti; G[b][a] = ti;
    }
    fill(dis,dis+600,inf);         //設定初值
    dis[c1] = 0;
    w[c1] = weight[c1]; num[c1] = 1;
    for (int i = 0; i < n; i++)           //迴圈一遍找有沒有沒有訪問過的點而且從起點到j最短
    {
        int u = -1; int minlen = inf;
        for (int j = 0; j < n; j++)
        {
            if (dis[j] < minlen&&vi[j]==0)    //沒有訪問過而且小於最短距離
            {
                u = j; minlen = dis[j];
            }
        }
        if (u == -1)break;
        vi[u] = 1;
        for (int k = 0; k < n; k++)
        {
            if (dis[u] + G[u][k] < dis[k]&&G[u][k]!=inf)
            {
                dis[k] = dis[u] + G[u][k];
                num[k] = num[u];
                w[k] = w[u] + weight[k];
            }
            else if (dis[u] + G[u][k]==dis[k])
            {
                num[k] = num[u]+num[k];
                if (w[k] < w[u] + weight[k])w[k] = w[u] + weight[k];
            }
        }
    }
    cout << num[c2] << " " << w[c2];
    return 0;
}