1. 程式人生 > 實用技巧 >【CTSC1999】月亮之眼

【CTSC1999】月亮之眼

Description

  吉兒是一家古董店的老闆娘,由於她經營有道,小店開得紅紅火火。昨天,吉兒無意之中得到了散落民間幾百年的珍寶—月亮之眼。吉兒深知“月亮之眼”價值連城:它是由許多珍珠相連而成的,工匠們用金線連線珍珠,每根金線連線兩個珍珠;同時又對每根金線染上兩種顏色,一半染成銀白色,一半染成黛黑色。由於吉兒自小熟讀古籍,所以還曉得“月亮之眼”的神祕傳說:“月亮之眼”原是一個古代寺廟的寶物,原本是掛在佛堂的一根頂樑柱上的,整個寶物垂直懸掛,所有珍珠排成一線,且都鑲嵌在柱子裡,而每一根金線又都是繃緊的,並且金線的銀白色一端始終在黛黑色一端的上方;然而,在一個月圓之夜,“月亮之眼”突然從柱裡飛出,掉落下來,寶物本身完好無損,只是僧侶們再也無法以原樣把“月亮之眼”嵌入柱子中了。吉兒望著這個神祕的寶物,回憶著童年讀到的傳說,頓時萌發出恢復“月亮之眼”的衝動,但是擺弄了幾天依舊沒有成功。

  現在,要麻煩您來幫助吉兒完成這項使命。
  您要設計一個程式,對於給定的“月亮之眼”進行周密分析,然後給出這串寶物幾百年前嵌在佛堂頂樑柱上的排列模樣。給定的“月亮之眼”有N個珍珠和P根金線,所有珍珠按一定順序有了一個序號:1、2…、N。

Input

輸入資料包含一個“月亮之眼”的特徵描述:
檔案第一行有兩個整數N和P,其中N表示寶物中的珍珠個數,P表示寶物中的金線根數;
以下P行描述珍珠連線情況:
檔案第I+1行有三個整數,Ri1,Ri2,Li。其中Ri1表示第I根金線的銀白色一端連線的珍珠序號;Ri2表示第I根金線的黛黑色一端連線的珍珠序號;Li表示第I根金線的長度。

Output

由於珍珠尺寸很小,所以幾個珍珠可以同時鑲嵌在一個位置上。
您的輸出資料描述的是“月亮之眼”各個珍珠在頂樑柱上的位置,輸出檔案共N行:
第I行,一個整數S,它表示標號為I的珍珠在頂樑柱上距離最高位置珍珠的距離。
注意:若無解則輸出僅一行,包含一個整數“-1”。

Sample Input

9 9
1 2 3
2 3 5
2 7 1
4 5 4
5 6 1
5 9 1
6 7 1
7 8 3
9 8 4

Sample Output

2
5
10
0
4
5
6
9
5

Hint

引數限定
1<=N<=255


樣例說明:
我們把輸入依次投射出來,從左到右,具體如下圖:

題意有些難懂 但結合圖片就不難理解了

因為輸出只是離最高的珠子的的距離 我們考慮帶權的並查集並採用路徑壓縮

對於一對珠子 X Y X在Y上方 距離為Z 當XY不在同一並查集時

則有兩種情況

一種在X並查集的樹根XX到Y的距離大於在Y的並查集的樹根YY到Y的距離 (即在這條直線上 XX 高於 YY)

此時連線X——Y 與 連線XX——YY同理 距離為 XX到Y距離去YY到Y的距離(d[x] + Z - d[y])

同理 當YY高於XX也是同理 距離為 YY到Y距離去XX到Y的距離(-d[x] - S + d[y])

當XY在同一並查集時 則必有X Y 到樹根距離為Z 否則不能繃直或連線

貼程式碼

#include<iostream>
#include<cstdio>
#define LL long long
#define f(a,b) for(long long i = (a); i <= (b); i++)
using namespace std;
long long n,m,sum;
long long fa[1000],d[3000];
long long begin,final,value,x,y;
void merge(long long xx,long long yy,long long sum)
{
    fa[xx] = yy, d[xx] = sum;
}
long long  get(long long x)
{
    if(x == fa[x]) return x;
    long long root = get(fa[x]);
    d[x] += d[fa[x]];
    return fa[x] = root;
}
int main()
{
    scanf("%lld%lld",&n,&m);
    f(1,n)fa[i] = i,d[i] = 0;
    f(1,m) 
    {
      scanf("%lld%lld%lld",&x,&y,&value);
      long long x_father = get(x),y_father = get(y);
      if(x_father == y_father)
      if(d[y] - d[x] != value) 
      {
          cout<<-1;
        return 0;
      }
      if(d[x] + value >= d[y]) merge(y_father,x_father,d[x] + value - d[y]);
      if(d[x] + value < d[y]) merge(x_father,y_father,d[y] - value - d[x]);
    }
    f(1,n) 
    long long QWQ = get(i);
    f(1,n)cout << d[i]<<endl;
}
View Code