HDU-1598-find the most comfortable road(暴力枚举+Kruskal最小生成树)

题意:

给出一个图,然后Q个询问,每次询问从一个节点到另一个节点,联通图中的“最大边和最小边之差”的最小值,但如果节点之间不连通,则输出-1.

思路:由于询问Q < 11,m < 1000,所以O(Q*n^2),Q*n^2 < 10^8,用最小生成树的思路,在给图上的边排好序的基础上,每次枚举最小边,然后做并查集枚举最大边,当查询的路径相通的时候,如果差值比上一次枚举最小边的差值小的时候,更新。


AC代码:

//AC
#include
#include
#include
#include
using namespace std;
#define maxn 20500
#define INF 9000000
int par[maxn], h[maxn], n, m, q;
struct node{
   int s, t, w;
};
bool cmp(node a, node b){
    return a.w < b.w;
}
vector ve;
void init(){
    for(int i = 0; i <= n; i++){
       par[i] = i;
       h[i] = 0;
    }
}

int Find(int x){
   if(par[x] == x) return x;
   return par[x] = Find(par[x]);
}

void Union(int a, int b){
   a = Find(a);
   b = Find(b);
   if(a != b){
     if(h[a] > h[b]) par[b] = par[a];
     else{
         if(h[a] == h[b]) h[b]++;
         par[a] = par[b];
     }
   }
}
int query(int a, int b){
    int ans = INF, j;
    for(int i = 0; i < ve.size(); i++){//枚举最小边
         init();
         for(j = i ; j < ve.size(); j++){
             int x = Find(ve[j].s), y = Find(ve[j].t);
             if(x != y){
                Union(x, y);
             }
             if(Find(a) == Find(b)) {  //找到最大边
                 if(ans > ve[j].w - ve[i].w)
                    ans = ve[j].w - ve[i].w;
                 break;
             }
         }
         if(j == m) break;  //如果j == m则不必继续往下枚举了
    }
    return ans;
}

void work(){
    ve.clear();
    init();
    for(int i = 0; i < m; i++){
        node n;
        scanf("%d%d%d", &n.s, &n.t, &n.w);
        ve.push_back(n);
    }
    sort(ve.begin(), ve.end(), cmp);
    scanf("%d", &q);
    for(int i = 0; i < q; i++){
       int a, b, c;
       scanf("%d%d", &a, &b);
       c = query(a, b);
       printf("%d\n", (c == INF) ? -1 : c);
    }
}
int main()
{
   while(scanf("%d%d", &n, &m) != EOF){
      init();
      work();
   }
   return 0;
}


你可能感兴趣的:(Union-find,Water,Problem,图论)