HDU1598 并查集+枚举

http://acm.hdu.edu.cn/showproblem.php?pid=1598

题意:给出一个无向图,每条边代表两点之间的同行速度,给出起点和终点,求出从起点到终点的路径的最小速度差。若无法从起点到终点,则输出-1。

思路:存储每条边的信息,按速度升序排序。按速度从小到大枚举边,然后依次往构建的树中添加边直到起点和终点在同一集合中。此时,最初添加的边的速度与最后添加的边的速度差为当前构造的路径的速度差,每次枚举结束后更新速度差。第一次枚举结束后若发现无法从起点到达终点,那么可以直接停止枚举。(第一次无法成功时,所有边均已添加到路径中,之后无论如何枚举也不可能构造出从起点到达终点的路径)代码从形式上来看很像kruskal,但并没有构建出最小生成树。所以我觉得真要分类的话,分到并查集中或许会好一些。(本来kruskal就依靠并查集实现)

 

#include<bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;
int n, m, pa[205];
struct Edge
{
    int u,v,val;
}eg[1005];

bool cmp(Edge a, Edge b)
{
    return a.val < b.val;
}

void init()
{
    for (int i=1;i<=n;i++)
        pa[i] = i;
}

int fnd(int x)
{
    if (pa[x]!=x) pa[x] = fnd(pa[x]);
    return pa[x];
}

void uni(int x,int y)
{
    int tx = fnd(x) , ty = fnd(y);
    if (tx!=ty)
        pa[tx] = ty;
}

int main()
{
    int q,st,ed; //询问数量,起点,终点
    while (scanf("%d %d",&n,&m)==2)
    {
        for (int i=0;i<m;i++)
        {
            int u,v,val; //边的两个点,边上的速度
            scanf("%d %d %d",&u,&v,&val);
            eg[i].v = v; eg[i].u = u; eg[i].val = val;
        }
        int ans = INF;
        scanf("%d",&q);
        sort(eg,eg+m,cmp); //将边按速度升序排序
        while (q--)
        {
            scanf("%d %d",&st,&ed);
            ans = INF;
            //将ans置为一个较大值,若之后ans不改变说明无法找到从起点到终点的路径
            for (int i=0;i<m;i++)
            {
                init();
                for (int j=i;j<m;j++)
                {
                    uni(eg[j].v,eg[j].u);
                    if (fnd(st) == fnd(ed))
                        ans = min(ans,eg[j].val - eg[i].val); 
                                        //起点与终点相连,更新ans
                }
                if (ans==INF) break; //可以结束枚举
            }
            if (ans == INF) printf("-1\n");
            else printf("%d\n",ans);
        }
    }
    return 0;
}
                                

 

posted @ 2016-08-08 15:00  LasNoire  阅读(490)  评论(0编辑  收藏  举报