1. 程式人生 > 其它 >狡猾的商人(帶權並查集)

狡猾的商人(帶權並查集)

題目:狡猾的商人

題目連結:https://ac.nowcoder.com/acm/problem/20044

題意:商人有一個賬本,賬本記錄為x y z,表示從x月到y月(區間左閉右閉)賺了z元,z為負數時表示虧損。問賬本記錄之間是否有衝突。

輸入:第一行輸入測試用例個數t。

接下來t個測試用例,每個測試用例第一行輸入n(總共的月數)和m(記錄的條數)。

接下來m行,每行三個整數x y z,表示一條賬本記錄。

題目保證:t < 100, n < 100, m < 1000, x <= y。

輸出:若賬本之間無衝突,則輸出true;否則,輸出false。

樣例輸入:

1

3 3

1 2 10

1 3 -5

3 3 -15

樣例輸出:

true

樣例解釋:第一個月到第二個月賺了10元,第三月虧了15元,第一個到第三月虧了5元。

題目分析:帶權並查集。

解題步驟:對於每條賬本記錄,若x和y在同一個集合,則判斷從x月到y月是不是賺了z元,若不是,則說明賬本記錄之間有衝突;若x和y不在同一個集合,則合併x和y。

需要注意的是,由於本題x和y都是閉區間,所以要把x – 1,或者y + 1,因為[x, y]之間有y – x + 1個月。

AC程式碼:

#include<iostream>

using namespace std;

const int N = 110;

int parent[N], val[N];

int find(int x){

if(x == parent[x]) return x;

int y = find(parent[x]);

val[x] += val[parent[x]];

return parent[x] = y;

}

void Union(int x, int y, int z){

int p1 = find(x), p2 = find(y);

parent[p1] = p2;

val[p1] = z + val[y] - val[x];

}

void solve(){

int n, m;

scanf("%d %d", &n, &m);

for(int i = 0;i <= n;i++){

parent[i] = i;

val[i] = 0;

}

int ans = 0;

while(m--){

int x, y, z;

scanf("%d %d %d", &x, &y, &z);

x--;

if(find(x) == find(y)){

if(val[x] - val[y] != z) ans = 1;

}

else Union(x, y, z);

}

if(ans == 0) printf("true\n");

else printf("false\n");

}

int main(void){

int t;

scanf("%d", &t);

while(t--) solve();

return 0;

}

時間複雜度:O(n + mlogm),路徑壓縮的並查集的時間複雜度接近於logn。

空間複雜度:O(n)。