pat甲级1003 单源最短路径问题

1、dijkstra算法
写法固定。中间犯了一个低级错误,N是多个地方都用到的边界数据,尽量不要改变N的值,比如while(N–)

#include <cstdio>
#include <climits>
#include <algorithm>

const int maxc = 500;
const int INF = INT_MAX;

int N, M, C1, C2;
int teams[maxc];
int graph[maxc][maxc]={};
bool confirmed[maxc]={}; //C1到该城市的最短距离是否已确定
int distance[maxc]; //从C1到i最短路径长度为distance[i]
int path[maxc]={}; //从C1到i有path[i]条最短路
int r_team[maxc]={}; //从C1到i在路径最短条件下,最多能累积r_team[i]个救援队

void init();
//在graph上执行djkstra算法,计算出三个数组的结果
void dijkstra();

int main(){
    scanf("%d%d%d%d", &N, &M, &C1, &C2);
    for(int i=0; i<N; i++) scanf("%d", &teams[i]);
    while(M--){
        int c1, c2, dis;
        scanf("%d%d%d", &c1, &c2, &dis);
        graph[c1][c2] = graph[c2][c1] = dis;
    }
    init();
    dijkstra();
    printf("%d %d", path[C2], r_team[C2]);

    return 0;
}

void init(){
    std::fill(distance, distance+N, INF);
    distance[C1] = 0;
    path[C1] = 1;
    r_team[C1] = teams[C1];
    return;
}

void dijkstra(){
    for(int k=0; k<N; k++){
        //循环N次,每次确定一个城市的最短距离,包括C1到C1也要确定一次
        //从distance数组中未确定的城市中找到最小的,该城市即确定了最短距离
        int city=-1, min_d=INF;
        for(int i=0; i<N; i++){
            if(!confirmed[i] && distance[i]<min_d){
                city = i;
                min_d = distance[i];
            }
        }
        //若所有未确定的城市距离都是INF,说明未确定的点与起点不连通
        if(city==-1) return;
        //否则到达该城市最短距离已确定
        confirmed[city] = true;
        //以city为中介,考察它能到达的未确定的顶点
        for(int i=0; i<N; i++){
            if(!confirmed[i] && graph[city][i]!=0){
                if(distance[city]+graph[city][i]<distance[i]){
                    //以city为中介,能缩短到i的距离。此为第一标准,不管r_team是否变大都更新其值
                    distance[i] = distance[city] + graph[city][i];
                    r_team[i] = r_team[city] + teams[i];
                    path[i] = path[city];
                }
                else if(distance[city]+graph[city][i]==distance[i]){
                    //以city为中介,和不以它为中介,到i的距离相等
                    path[i] += path[city];
                    //第二标准生效
                    if(r_team[city]+teams[i]>r_team[i]){
                        r_team[i] = r_team[city]+teams[i];
                    }
                }
            }
        }
    }
    return;
}

2、Bellman Ford算法

#include <cstdio>
#include <vector>
#include <set>
#include <climits>
#include <algorithm>

using namespace std;

const int maxv = 500;
const int INF = INT_MAX;

struct edge{
    int e_end, e_weight;
    edge(int a, int b): e_end(a), e_weight(b) {}
};

int N, M, S, D;
int v_weight[maxv], d[maxv];
int path_count[maxv]={};
int team[maxv]={};
vector<edge> graph[maxv];
set<int> pre[maxv];

void init();
void bellmanFord();

int main(){
    scanf("%d%d%d%d", &N, &M, &S, &D);
    for(int i=0; i<N; i++) scanf("%d", &v_weight[i]);
    while(M--){
        int c1, c2, l;
        scanf("%d%d%d", &c1, &c2, &l);
        graph[c1].push_back(edge(c2, l));
        graph[c2].push_back(edge(c1, l));
    }
    init();
    bellmanFord();
    printf("%d %d", path_count[D], team[D]);

    return 0;
}

void init(){
    fill(d, d+N, INF);
    d[S] = 0;
    path_count[S] = 1;
    team[S] = v_weight[S];
    return;
}

void bellmanFord(){
    for(int k=0; k<N-1; k++){
        //最多N-1次循环
        for(int i=0; i<N; i++){
            //每个顶点i
            if(d[i]==INF) continue; //重要
            int e = graph[i].size();
            for(int j=0; j<e; j++){
                //每条边i -> v
                int v = graph[i][j].e_end;
                int w = graph[i][j].e_weight;
                if(d[i]+w<d[v]){
                    //第一标准更优。找到更短路径
                    d[v] = d[i] + w;
                    team[v] = team[i] + v_weight[v];
                    path_count[v] = path_count[i];
                    pre[v].clear();
                    pre[v].insert(i);
                }
                else if(d[i]+w==d[v]){
                    //第一标准失效。找到长度相同的另一条路
                    //重新统计路径条数
                    pre[v].insert(i);
                    path_count[v] = 0;
                    for(set<int>::iterator it=pre[v].begin(); it!=pre[v].end(); it++){
                        path_count[v] += path_count[*it];
                    }
                    //第二标准更优
                    if(team[i]+v_weight[v]>team[v]){
                        team[v] = team[i] + v_weight[v];
                    }
                }
            }
        }
    }
    return;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值