1003 Emergency C++

分析

使用Dijkstra算法或Bellman-Ford都可以

算法一:Dijkstra

//
// Created by CyIce on 2021/1/19.
//

#include <stdio.h>
#include <algorithm>

using namespace std;

const int MAXV = 510;
const int INF = 0x3fffffff;

//Team:每个城市的救援队数量
int n, G[MAXV][MAXV], Team[MAXV], pathNum = 0, teamNum = 0;
//d[i]:起点到i的最短路径,t[i]:起点到i最短路径下救援队的最大数量,num[i]:起点到i最短路径的数目
int d[MAXV], t[MAXV] = {0}, num[MAXV]={0};
bool vis[MAXV] = {false};

void Dijkstra(int s, int e) {
    fill(d, d + MAXV, INF);
    num[s]=1;
    d[s] = 0;
    t[s] = Team[s];
    for (int i = 0; i < n; ++i) {
        int u = -1, MIN = INF;
        for (int j = 0; j < n; ++j) {
            if (!vis[j] && d[j] < MIN) {
                u = j;
                MIN = d[j];
            }
        }
        if (u == -1) return;
        vis[u] = true;
        for (int v = 0; v < n; ++v) {
            if (!vis[v] && G[u][v] != INF) {
                if (d[u] + G[u][v] < d[v]) {
                    d[v] = d[u] + G[u][v];
                    t[v] = t[u] + Team[v];
                    num[v] = num[u];
                } else if (d[u] + G[u][v] == d[v]) {
                    num[v] += num[u];
                    if (t[u] + Team[v] > t[v])
                        t[v] = t[u] + Team[v];
                }
            }
        }
    }

    pathNum = num[e];
    teamNum = t[e];
}

int main() {
    int edge, s, e;
    fill(G[0], G[0] + MAXV * MAXV, INF);
    scanf("%d%d%d%d", &n, &edge, &s, &e);
    for (int i = 0; i < n; ++i) {
        scanf("%d", &Team[i]);
    }
    for (int i = 0; i < edge; ++i) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        G[a][b] = c;
        G[b][a] = c;
    }
    Dijkstra(s, e);
    printf("%d %d\n", pathNum, teamNum);

    return 0;
}

算法二:Bellman-Ford

//
// Created by CyIce on 2021/1/24.
//

//Bellman-Ford算法

#include <stdio.h>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

//边结构体
struct edge {
    int v, dis;
};

const int MAXV = 510;
//邻接矩阵
vector<edge> Adj[MAXV];
int N, V[MAXV], INF = 0x3fffffff;
//最短路径和最大救援队数量
int d[MAXV], value[MAXV] = {0};
//前驱节点,因为每个节点会重复访问,用set避免同一节点重复添加
set<int> pre[MAXV];

bool bellman(int s) {
    fill(d, d + MAXV, INF);
    d[s] = 0;
    value[s] = V[s];
    for (int i = 0; i < N - 1; ++i) {
        for (int u = 0; u < N; ++u) {
            for (int j = 0; j < Adj[u].size(); ++j) {
                int v = Adj[u][j].v;
                int dis = Adj[u][j].dis;
                if (d[u] + dis < d[v]) {
                    d[v] = d[u] + dis;
                    value[v] = value[u] + V[v];
                    pre[v].clear();
                    pre[v].insert(u);
                } else if (d[u] + dis == d[v]) {
                    if(value[u] + V[v] > value[v]){
                        value[v] = value[u] + V[v];
                    }
                    pre[v].insert(u);
                }
            }
        }
    }

    for (int i = 0; i < N - 1; ++i) {
        for (int u = 0; u < N; ++u) {
            for (int j = 0; j < Adj[u].size(); ++j) {
                int v = Adj[u][j].v;
                int dis = Adj[u][j].dis;
                if (d[u] + dis < d[v]) {
                    return false;
                }
            }
        }
    }
    return true;
}

//递归计算最短路径条数
//s:起点,v:当前节点
int pathNum(int s,int v){
    if(v == s){
        return 1;
    } else{
        set<int>::iterator it;
        int num=0;
        for(it = pre[v].begin();it!=pre[v].end();it++){
            num+=pathNum(s,*it);
        }
        return num;
    }
}

int main() {
    int m, s, end;

    scanf("%d%d%d%d", &N, &m, &s, &end);
    for (int i = 0; i < N; ++i) {
        scanf("%d", &V[i]);
    }
    for (int i = 0; i < m; ++i) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        Adj[a].push_back(edge{b, c});
        Adj[b].push_back(edge{a, c});
    }

    if (bellman(s)) {
        printf("%d %d\n", pathNum(s,end), value[end]);
    }

    return 0;
}

解法三:SPFA (测试点2未通过,原因未知)

#include <stdio.h>
#include <vector>
#include <queue>
#include <set>
#include <algorithm>

using namespace std;

struct node {
    int v, dis;
};

const int MAXV = 510;
int INF = 0x3fffffff;

vector<node> Adj[MAXV];
set<int> pre[MAXV];
int N, d[MAXV], value[MAXV] = {0}, V[MAXV], num[MAXV] = {0};
bool inq[MAXV] = {false};


bool SPFA(int s) {
    fill(d, d + MAXV, INF);
    queue<int> q;
    q.push(s);
    inq[s] = true;
    num[s]++;
    d[s] = 0;
    value[s] = V[s];
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        inq[u] = false;
        for (int i = 0; i < Adj[u].size(); ++i) {
            int v = Adj[u][i].v;
            int dis = Adj[u][i].dis;
            if (d[u] + dis < d[v]) {
                d[v] = d[u] + dis;
                value[v] = value[u] + V[v];
                pre[v].clear();
                pre[v].insert(u);
                if (!inq[v]) {
                    q.push(v);
                    inq[v] = true;
                    num[v]++;
                    if (num[v] >= N)
                        return false;
                }
            } else if (d[u] + dis == d[v]){
                pre[v].insert(u);
                if(value[u] + V[v] > value[v]){
                    value[v] = value[u] + V[v];
                }
            }
        }
    }
    return true;
}
//递归计算最短路径条数
//s:起点,v:当前节点
int pathNum(int s,int v){
    if(v == s){
        return 1;
    } else{
        set<int>::iterator it;
        int num=0;
        for(it = pre[v].begin();it!=pre[v].end();it++){
            num+=pathNum(s,*it);
        }
        return num;
    }
}


int main() {
    int m, s, end;

    scanf("%d%d%d%d", &N, &m, &s, &end);
    for (int i = 0; i < N; ++i) {
        scanf("%d", &V[i]);
    }
    for (int i = 0; i < m; ++i) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        Adj[a].push_back(node{b, c});
        Adj[b].push_back(node{a, c});
    }

    if (SPFA(s)) {
        printf("%d %d\n", pathNum(s, end), value[end]);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值