How Many Tables——HDU 1213
技術標籤:模擬題
How Many Tables
題目
Today is Ignatius’ birthday. He invites a lot of friends. Now it’s dinner time. Ignatius wants to know how many tables he needs at least. You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers.
One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table.
For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least.
Input
The input starts with an integer T(1<=T<=25) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N,M<=1000). N indicates the number of friends, the friends are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other. There will be a blank line between two cases.
Output
For each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks.
大概意思就是A認識B,B認識C,也就意味著A認識C。這樣他們就可以坐在一個桌子上。問你輸入T個測試例子,每個測試例子的第一行是N和M兩個數,N表示來的人數,M表示他們之間有多少人是認識的。給你這一系列的資料後,問你要多少個桌子才能坐得下所有人?
思路
其實就是一個簡單的並查集,先建立一個數組,並且將每個人都分在同一個桌子,每次輸入一對關係的時候,就判斷一下他們是否在同一個父節點上面,即是否在同一桌,如果是,那就繼續,不是的話,那麼需要合併其中一個到另外的一個桌子。依次詢問,直到結束。
程式碼
import java.util.Scanner;
public class Main {
static int father[]=new int[1005];
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
int T=reader.nextInt();//測試例子數目
//進行T次詢問
for (int g=0;g<T;++g)
{
int N=reader.nextInt();//原始的人數
//初始化,每個人都是自成一派
for (int i=1;i<=N;++i)
father[i]=i;
int M=reader.nextInt();//相關聯的次數
for (int i=0;i<M;++i)
{
int a=reader.nextInt();
int b=reader.nextInt();
if (findfather(a)!=findfather(b))
{
union(a,b);
}
}
int ans=0;
for (int i=1;i<=N;++i)
if (father[i]==i)
++ans;
System.out.println(ans);
}
}
//尋找每個人的根節點,並且進行路徑壓縮,即當前點的父節點不是她自己,那麼就通過他的父節點繼續尋找父節點的父節點,直到找到為止,並且將當前的父節點修改為最大的父節點,壓縮路徑,使得每個結點都直接跟父節點相關聯
private static int findfather(int a) {
if (a==father[a])
return a;
father[a]=findfather(father[a]);
return father[a];
}
//路徑壓縮,先尋找到兩個點的父節點,如果兩個點的父節點不一樣,那麼需要將其中的一個父節點改變為另一個的父節點。
private static void union(int a, int b) {
a=findfather(a);
b=findfather(b);
if (a!=b)
father[b]=a;
}
}
結果
就是一個並查集的簡單應用,複習一下。