hdu 1598 find the most comfortable road (并查集+枚举下界)

find the most comfortable road



题目链接:Problem - 1598

题目大意:求一条差值最小的路。

题目分析:

思路一:深搜,一一枚举各条合法的路,如果此路连接了起始点和结束点,计算此时的差,然后比较得出差得最小值。
(路的个数有1000条,此方法肯定会超时)

思路二:dijkstra,找出一条最短路,一路上记录最大值,最小值,比如1->2->5,记录Low[5][2].maxs,和low[5][2].mins(5是pos,2是pre)最后对low[e][]扫一遍,得出最小值。(此方法只能保留一个前驱的mins,maxs,比如2 -> 5有[mins,maxs]=[2,5]和[1,4],2个范围不冲突,应全部保留,此方法值能保留一个,wa)

思路三:并查集+枚举下界。对路的长度进行排序,枚举下界mins,进行并查集操作,因为每次枚举都是先选小边再选大边,所以一旦满足finds(end)=finds(start),所得到的差值一定是此下界最小的情况。

思路分析:
1)存路并排序(road[1005])
2)枚举下界,mins值,每次都进行并查集操作,当start和end点根相同时记录cha,比较出所有情况下cha的最小值。

笔者心得:做图论题一是考虑方法,而是考虑复杂度,否则一直会死在错误算法里,笔者就再思路二上挣扎了1天。

贴AC代码:
#include <stdio.h> //定义输入/输出函数
#include <limits.h> //定义各种数据类型最值常量
#include <math.h> //定义数学函数
#include <stdlib.h> //定义杂项函数及内存分配函数
#include <string.h> //字符串处理
#include <algorithm>//算法
#include <queue>//队列
#include <stack>//栈
#include <vector>
using namespace std;
int n, m, q, mins, maxs, ans, s, e;
int re[205];
struct node{
    int from, to, cost;
};
node road[1005];
int finds(int x){
    if (re[x] == x) return x;
    else return re[x] = finds(re[x]);
}
int cmp(node a, node b){
    return a.cost < b.cost;
}
int main()
{
    while (scanf("%d", &n) != EOF && n){
        scanf("%d", &m);
        for (int i = 0; i < m; i++){
            scanf("%d%d%d", &road[i].from, &road[i].to, &road[i].cost);
        }
        sort(road, road + m, cmp);
        scanf("%d", &q);
        while (q--){
            scanf("%d%d", &s, &e);
            ans = 1000005;
            int flag = 0;
            for (int i = 0; i < m; i++){
                //枚举min;
                mins = 1000005;
                maxs = 0;
                for (int j = 1; j <= n; j++)
                    re[j] = j;
                for (int j = i; j < m; j++){
                    //kruskal
                    if (finds(road[j].from) == finds(road[j].to)) continue;
                    re[finds(road[j].from)] = finds(road[j].to);
                    mins = min(road[j].cost, mins);
                    maxs = max(road[j].cost, maxs);
                    //printf("%d <-> %d == [%d, %d]\n", road[j].from, road[j].to, mins, maxs);
                    if (finds(s) == finds(e)){
                        flag = 1;
                        if (ans > maxs - mins)
                            ans = maxs - mins;
                        break;
                    }
                }
            }
            if (flag == 1) printf("%d\n", ans);
            else printf("-1\n");
        }
    }
}

贴思路二代码:
#include <stdio.h> //定义输入/输出函数
#include <limits.h> //定义各种数据类型最值常量
#include <math.h> //定义数学函数
#include <stdlib.h> //定义杂项函数及内存分配函数
#include <string.h> //字符串处理
#include <algorithm>//算法
#include <queue>//队列
#include <stack>//栈
#include <vector>
using namespace std;
int n, m, Q, s, e, tmp;
int map[205][205];
struct node{
    int mins, maxs, cha;
};
node low[205];
bool vis[205];
void input()
{
    int a, b, c;
    scanf("%d%d%d", &a, &b, &c);
    map[a][b] = c;
    map[b][a] = c;
}
void dijkstra()
{
    memset(low, 0, sizeof(low));
    for (int i = 0; i < 205; i++)
        low[i].cha = 1000005;
    memset(vis, 0, sizeof(vis));
    //int flag = 1;
    for (int i = 1; i <= n; i ++){
        if (map[s][i] == 0) continue;
        low[i].mins = low[i].maxs = map[s][i];
        low[i].cha = 0;
        // flag = 0;
    }
    //从s出发,初始化
    //if (flag == 1) return;
    // 是否连通
    vis[s] = 1;
    for (int i = 0; i < n-1;i ++){
        unsigned int cmp = 1000005;
        tmp = 0;
        for (int j = 1; j <= n; j++){
            if (low[j].cha < cmp && vis[j] == 0){
                cmp = low[j].cha;
                tmp = j;
            }
        }
        if (tmp == 0) continue;
        vis[tmp] = 1;
        for (int j = 1; j <= n; j++){
            if (vis[j] == 1) continue;
            if (map[tmp][j] == 0) continue;
            int k = max(low[tmp].maxs, map[tmp][j]);
            int kk = min(low[tmp].mins, map[tmp][j]);
            if (low[j].cha > k - kk){
                low[j].cha = k - kk;
                low[j].maxs = k;
                low[j].mins = kk;
            }
            //printf("%d(%d,%d)  --> %d == %d\n", tmp,low[j].maxs, low[j].mins, j, low[j].cha);
        }
    }
}
int main()
{
    while (scanf("%d", &n) != EOF && n){
        scanf("%d", &m);
        memset(map, 0, sizeof(map));
        for (int i = 0; i < m; i ++)
            input();
        scanf("%d", &Q);
        while (Q--){
            scanf("%d%d", &s, &e);
            dijkstra();
            if (low[e].cha != 1000005)printf("%d\n", low[e].cha);
            else printf("-1\n");
        }
    }
}

贴思路一代码:
#include <stdio.h> //定义输入/输出函数
#include <limits.h> //定义各种数据类型最值常量
#include <math.h> //定义数学函数
#include <stdlib.h> //定义杂项函数及内存分配函数
#include <string.h> //字符串处理
#include <algorithm>//算法
#include <queue>//队列
#include <stack>//栈
#include <vector>
using namespace std;
int n, m, q, mins, maxs, s, e, couts, ans;
bool vis[205];
int map[205][205];
int road[205];
void dfs(int loc)
{
    if (loc == e){
        maxs = 0;
        mins = 1000005;
        for (int j = 0; j < couts; j++){
            if (road[j] > maxs) maxs = road[j];
            if (road[j] < mins) mins = road[j];
        }
        if (ans > maxs - mins)
            ans = maxs - mins;
        return;
    }
    for (int i = 1; i <= n; i++){
        if (vis[i] == 1) continue;
        if (map[loc][i] == 0) continue;
        road[couts++] = map[loc][i];
        vis[i] = 1;
        dfs(i);
        vis[i] = 0;
        couts--;
    }
}
int main()
{
    while(scanf("%d", &n) != EOF && n){
        scanf("%d", &m);
        memset(map, 0, sizeof(map));
        while(m--){
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            map[a][b] = map[b][a] = c;
        }
        scanf("%d", &q);
        while (q--){
            scanf("%d%d", &s, &e);
            memset(vis, 0, sizeof(vis));
            memset(road, 0, sizeof(road));
            couts = 0;
            vis[s] = 1;
            ans = 1000005;
            if (s == e){
            	printf("0\n");
            	continue;
            }
            dfs(s);
            if (ans != 1000005) printf("%d\n", ans);
            else printf("-1\n");
        }
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值