HDU1598 并查集(有点难度哦)//感觉又有点像和宽度优先搜索有点结合

find the most comfortable road

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5585    Accepted Submission(s): 2415


Problem Description
XX星有许多城市,城市之间通过一种奇怪的高速公路SARS(Super Air Roam Structure---超级空中漫游结构)进行交流,每条SARS都对行驶在上面的Flycar限制了固定的Speed,同时XX星人对 Flycar的“舒适度”有特殊要求,即乘坐过程中最高速度与最低速度的差越小乘坐越舒服 ,(理解为SARS的限速要求,flycar必须瞬间提速/降速,痛苦呀 ),
但XX星人对时间却没那么多要求。要你找出一条城市间的最舒适的路径。(SARS是双向的)。
 

Input
输入包括多个测试实例,每个实例包括:
第一行有2个正整数n (1<n<=200)和m (m<=1000),表示有N个城市和M条SARS。
接下来的行是三个正整数StartCity,EndCity,speed,表示从表面上看StartCity到EndCity,限速为speedSARS。speed<=1000000
然后是一个正整数Q(Q<11),表示寻路的个数。
接下来Q行每行有2个正整数Start,End, 表示寻路的起终点。
 

Output
每个寻路要求打印一行,仅输出一个非负整数表示最佳路线的舒适度最高速与最低速的差。如果起点和终点不能到达,那么输出-1。
 

Sample Input
   
   
   
   
4 4 1 2 2 2 3 4 1 4 1 3 4 2 2 1 3 1 2
 

Sample Output
   
   
   
   
1 0


遇到的问题和解题思路:(表示这道题目看了讨论才会做的)

       个人在做题的时候遇到如下的问题,想法也是如下(   

                   这一个循环里面。For循环中要求出差值的最小值的那个点,这个点可能比目前最小值还要小,也有可能比目前最大值还要大。假设刚开始的差值就是inf(因为不可能不走),所以①同根same,并且不是inf,才能够移动。②移动了,但是移动之后的差值,可能会比之前的要大。③移动以后所移向的那个值可能是现在的最大值或者是最小值。)

       但是做了以后感觉有一个地方卡住了,就是如何判断什么时候是差值是最小的,什么时候选择另外一条边。

       这道题目最难的一点就是如何选择边。

       如果按照贪心法来计算的话,每次都挑选差值最小的就可以了,但是这个算法会出错的一个地方就是,如果贪心法的尽头走到的其中一个点只有一条路,而且这条路的值非常的大,那么不得不选,这个时候肯定就不如其他的边走的方便了。因此,分析以后又感觉像是搜索。

    

        看了某位大神的讨论中的题解以后,感觉,恩,感觉就像是搜索的解法,不过只是运用了这个思路罢了。

        先将所加入的边从大到小排列,然后用O(m*(n + m))的复杂度,第一层循环m是i=1开始循环到m,将每条边都遍历过去。第二个循环是n,将所有的par都复原。第三层就是寻找。具体的看代码吧。


给出代码:



#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define inf 0x3f3f3f3f using namespace std; int n, m, q, a, b; int par[1000 + 50]; struct edge{ int from, to, cost; }; edge ed[1000 + 50]; bool cmp(const edge &e1, const edge &e2){ return e1.cost> e2.cost; } int find(int x){ if(par[x] == x) return x; return par[x] = find(par[x]); } void solve(){ int ans = inf; for(int i = 1; i <= m; i++){//一共有m条边,看看什么时候连在一起了,就是什么时候的 for(int j = 1; j <= n; j++){ par[j] = j;//让每次刚开始都是相对独立的 } int k; for(k = i; k <= m; k++){ int r1 = find(ed[k].from); int r2 = find(ed[k].to); if(r1 != r2){ par[r1] = r2; } if(find(a) == find(b)){//如果这个条件成立了,就说明在这一个时刻所挑选的边,使得两个相连了 if(ans > ed[i].cost - ed[k].cost){ ans = ed[i].cost - ed[k].cost; //printf("ans = %d\n"); } break; } } if(k == m+1)break;//再往后面循环下去,也不会连在一起了 //printf("ans = %d\n"); } if(ans == inf)printf("-1\n"); else printf("%d\n", ans); } int main(){ while(scanf("%d%d", &n, &m)!=EOF){ for(int i = 1; i <= m; i++){ scanf("%d%d%d", &ed[i].from, &ed[i].to, &ed[i].cost); } sort(ed + 1, ed + m + 1, cmp); scanf("%d", &q); while(q--){ scanf("%d%d", &a, &b); solve(); } } return 0; } </cmath></cstring></algorithm></cstdio>

你可能感兴趣的:(HDU1598 并查集(有点难度哦)//感觉又有点像和宽度优先搜索有点结合)