UVA 10816 Travel in Desert 最短路+Kruscal

题意:给你一个n个点m条边的无向图 每条边有一个长度和一个温度 问你找出一条从起点到终点 最大温度最小的路 如果存在多条 则输出距离最短的那一条

思路:这道题目有两种方法 第一种就是二分温度跑最短路 我用的是第二种方法 即 先求出最小生成树 最低温度一定存在于最小生成树中 然后dfs找出起点到终点的最大温度 跑一边spfa 过滤掉温度大于该温度的边 记录前驱结点 最后输出即可 代码写的有点乱 - -


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

#define bug puts("bug")

const int maxn = 100 + 10;
const int maxe = 20000 + 10;
const double INF = 1e9;

struct Edge{
    int v;
    double t, d;
    int next;
    Edge(int v = 0, double t = 0, double d = 0, int next = 0) : v(v), t(t), d(d), next(next) {}
};

struct Edge2{
    int u, v;
    double t;
    Edge2(int u = 0, int v= 0, double t = 0) : u(u), v(v), t(t) {}
    bool operator < (const Edge2 &rhs) const{
        return t < rhs.t;
    }
};

int STACK[maxn], top;
int vis[maxn];
int pre[maxn];
int pa[maxn];
double dist[maxn];
double cost[maxn];//到起点的最大温度
int n, m, st, ed;
int Head[2][maxn], cntE[2];
Edge edge[2][maxe];
Edge2 e[maxe];

void init(){
    memset(Head, -1, sizeof(Head));
    cntE[1] = cntE[0] = 0;
}

void add(int u, int v, double t, double d, int i){
    edge[i][cntE[i]] = Edge(v, t, d, Head[i][u]);
    Head[i][u] = cntE[i]++;
    edge[i][cntE[i]] = Edge(u, t, d, Head[i][v]);
    Head[i][v] = cntE[i]++;
}

int find_set(int x){
    return pa[x] == x ? x : pa[x] = find_set(pa[x]);
}

void Kruscal(){
    for(int i = 0;i  < n; i++) pa[i] = i;
    sort(e, e + m);
    int cnt = 0;
    for(int i = 0; i < m;i++){
        int x= find_set(e[i].u);
        int y = find_set(e[i].v);
        if(x != y){
            pa[x] = y;
            add(e[i].u, e[i].v, e[i].t, 0, 1);
            if(++cnt == n-1) return;
        }
    }
}

void spfa(int s, double max_t){
    memset(vis, 0, sizeof(vis));
    for(int i = 0; i < n; i++) dist[i] = INF;
    dist[s] = 0;
    vis[s] = 1;
    top = 0;
    STACK[top++] = s;
    while(top){
        int u = STACK[--top];
        vis[u] = 0;
        for(int i = Head[0][u]; ~i; i = edge[0][i].next){
            int v = edge[0][i].v;
            if(edge[0][i].t > max_t) continue;
            if(dist[v] > dist[u] + edge[0][i].d){
                dist[v] = dist[u] + edge[0][i].d;
                pre[v] = u;
                if(!vis[v]){
                    vis[v] = 1;
                    STACK[top++] = v;
                }
            }
        }
    }
}

void dfs(int u, double cur_max){
    vis[u] = 1;
    for(int i = Head[1][u]; ~i; i = edge[1][i].next){
        int v = edge[1][i].v;
        if(vis[v]) continue;
        cost[v] = max(cur_max, edge[1][i].t);
        dfs(v, cost[v]);
    }
}

void print(int x){
    if(pre[x] == -1){
        printf("%d", x + 1);
        return;
    }
    print(pre[x]);
    printf(" %d", x + 1);
}

void solve(){
    scanf("%d%d", &st, &ed);
    --st; --ed;
    init();
    for(int i = 0; i < m; i++){
        int u, v;
        double t, d;
        scanf("%d%d%lf%lf", &u, &v, &t, &d);
        --u; --v;
        add(u, v, t, d, 0);
        e[i] = Edge2(u, v, t);
    }
    Kruscal();
    memset(cost, 0, sizeof(cost));
    memset(vis, 0, sizeof(vis));
    memset(pre, -1, sizeof(pre));
    dfs(st, 0);
    spfa(st, cost[ed]);
    print(ed);
    printf("\n");
    printf("%.1lf %.1lf\n", dist[ed], cost[ed]);
}

int main()
{
    while(scanf("%d%d", &n, &m) != EOF) solve();
    return 0;
}
/*
6 9
6 1
1 2 37.1 10.2
2 3 40.5 20.7
3 4 38.3 19.0
3 1 38.3 15.8
4 5 39.7 11.1
6 3 36.0 22.5
5 6 43.9 10.2
2 6 44.2 15.2
4 6 34.2 1.00
*/


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值