CJOJ 1275【HAOI2006】旅行

旅行

Description

Z小鎮是一個景色宜人的地方,吸引來自各地觀光客來此旅遊觀光。Z小鎮附近共有N個景點(編號爲1,2,3...N),這些景點被M條道路連接着,所有道路都是雙向的,兩個景點之間可能有多條道路連接着。也許是爲了保護該地的旅遊資源,Z小鎮有個奇怪的規定,就是對於一條給定的公路Ri,任何在該公路上行駛的車輛速度必須爲Vi。速度變化太快使得遊客們很不舒服,因此從一個景點前往另一個景點的時候,大家都希望選擇行使過程中最大速度和最小速度的比儘可能小的路線,也就是所謂最舒適路線。

Input

第一行包括兩個整數: N 和 M
接下來的M行每行包含三個正整數: x,y和v。表示景點x到景點y之間有一條雙向公路,車輛必須以速度v在該公路上行駛。最後一行包含兩個正整數s,t,表示想知道從景點s到景點t最大最小速度比最小的路徑。s和t不可能相同。

Output

如果景點s到景點t沒有路徑,輸出“IMPOSSIBLE”。否則輸出一個數,表示最小的速度比。如果需要,輸出一個既約分數。

Sample Input

樣例1:
4 2
1 2 1
3 4 2
1 4
樣例2:
3 3
1 2 10
1 2 5
2 3 8
1 3
樣例3:
3 2
1 2 2
2 3 4
1 3

Sample Output

樣例1:
IMPOSSIBLE
樣例2:
5/4
樣例3:
2

Hint

0<N<=500;
0<M<=5000;

Source

HAOI2006

Solution

並查集

將每條邊按速度從小到大排序,然後枚舉起邊,從起邊開始並集,如果加入這條邊後起點、終點在一個集合裏面(路是通的),那麼這一條邊就是在該起邊下速度最大的邊,然後從這條邊開始倒搜,類似的找到最小邊(注意一定要找一邊,因爲可能去掉某一些正推時選的邊,也能使終點和起點聯通,而去掉這些邊後,最小速度才能儘可能大,從而使比值更優),然後更新起邊是最小邊的下一條邊(最小邊到之前起邊之間的邊顯然是無用邊),比較每一次起邊時的比值,更新答案

對於不通路的情況:沒有邊能夠在當前起邊的情況下,使起、終點相同;但需注意如果二者不在同一集合有兩種可能:當前起邊不符合但之前有起邊符合,或從始至終就沒有起邊符合.但只有第二種情況需要輸出無解

Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <map>
#include <vector>
#include <queue>
#define M 5010
#define N 510
#define inf 1000000010
#define LL long long
using namespace std;

struct node {
  int from, to, v;
} e[M];
int n, m, s, t, now = 1, fa[N], x, maxx, minx, temp1 = 1, temp2;

inline bool comp(node x, node y) {
  return x.v < y.v;
}

inline int findfa(int x) {
  return x == fa[x] ? x : fa[x] = findfa(fa[x]);
}

inline int gcd(int x, int y) {
  return (x % y == 0) ? y : gcd(y, x % y);
}

int main() {
  freopen("comf.in", "r", stdin);
  freopen("comf.out", "w", stdout);
  scanf("%d %d", &n, &m);
  for (int i = 1; i <= m; ++i) scanf("%d %d %d", &e[i].from, &e[i].to, &e[i].v);
  sort(e + 1, e + 1 + m, comp);
  scanf("%d %d", &s, &t);
  while (now <= m) {
    maxx = minx = -1;
    for (int i = 1; i <= n; ++i) fa[i] = i;
    for (x = now; x <= m; ++x) {
      int u = findfa(e[x].from), v = findfa(e[x].to);
      fa[u] = v;
      if (findfa(s) == findfa(t)) {maxx = e[x].v; break;}
    }
    if (maxx == -1) {
      if (!temp2) {printf("IMPOSSIBLE\n"); return 0;}
      else break;
    }
    for (int i = 1; i <= n; ++i) fa[i] = i;
    for (; x > 0; --x) {
      int u = findfa(e[x].from), v = findfa(e[x].to);
      fa[u] = v;
      if (findfa(s) == findfa(t)) {minx = e[x].v; break;}
    }
    if (maxx == -1) {
      if (!temp2) {printf("IMPOSSIBLE\n"); return 0;}
      else break;
    }
    now = x + 1;
    int k = gcd(maxx, minx); maxx /= k, minx /= k;
    if (temp1 * minx > temp2 * maxx) temp1 = maxx, temp2 = minx;
  }
  if (temp1 % temp2) printf("%d/%d\n", temp1, temp2);
  else printf("%d\n", temp1 / temp2);
  return 0;
}

Summary

考試的時候寫了一個暴力搜索,連樣例2都過不了,表示不看題解絕對想不到並查集……


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章