Rank HDU - 1704(藉由本題說明並查集與傳遞閉包的區別)
更新:突然想明白了,本題不可以用並查集來做。
我原來的思路是,比如通過並查集得到3個集合,每個集合的元素個數分別是7,8,9那麼最終無法判斷的個數就是7*8+7*9+8*9。但是並查集只能判斷他們是否屬於同一個集合,而不能判斷一個集合內部的每兩個元素之間是否有輸贏關係。比如輸入1 2和1 3,由並查集可以得到123屬於同一個集合,而不能判斷2號和3號之間的輸贏關係。而且本題抽象一下,可以看作是求每兩個元素之間不能比較大小的個數。所以本題只能用傳遞閉包。藉由本題也可以說明並查集與傳遞閉包的關係,讀者可以仔細體會一下。
本題可以用傳遞閉包來做,也可以用並查集來做,用並查集做的思想就是算出每一個集合的元素個數,然後兩兩相乘,將乘積累加起來。但為什麼一直WA,求大佬指導一二。
#include <stdio.h>
#include <string.h>int tree[501];
int num[501];int findRoot(int x)
{
if(tree[x] == x)
return x;
int tmp = findRoot(tree[x]);
tree[x] = tmp;
return tmp;
}int main()
{
int k, n, m;
scanf("%d", &k);
while(k--)
{
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++)
{
tree[i] = i;
num[i] = 1;
}
int a, b;
for(int i = 0; i < m; i++)
{
scanf("%d %d", &a, &b);
a = findRoot(a);
b = findRoot(b);
if(a != b)
{
tree[b] = a;
num[a] += num[b];
}
}
int tmp[250];
int id = 0;
bool flag =false;
for(int i = 1; i <= n; i++)
{
if(num[i] == 1)
continue;
if(num[i] == n)
{
flag = true;
break;
}
tmp[id++] = num[i];
}
if(flag)
printf("0\n");
else
{
int ans = 0;
for(int i = 0; i < id; i++)
for(int j = i+1; j < id; j++)
ans += tmp[i]*tmp[j];
printf("%d\n", ans);
}
}
return 0;
}