並查集Poj
POJ_2492 A Bug’s Life
用兩倍的陣列表示,當輸入x, y時,(兩者為異性),那麼x + n, y 和 x, y + n 則為同性(合併即可),(食物鏈的化簡版)
package POJ; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StreamTokenizer; public class Poj_2492 { static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out)); public static int nextInt() throws IOException { in.nextToken(); return (int) in.nval; } public static String next() throws IOException { in.nextToken(); return (String) in.sval; } static final int MAXN = 5000; static int par[] = new int[MAXN]; public static void main(String[] args) throws IOException { int t, n, m; t = nextInt(); for(int i = 1; i <= t; i++) { n = nextInt(); m = nextInt(); Init(n * 2); boolean flag = true; int x, y; while(m-- >0) { x = nextInt(); y = nextInt(); if(judge(x, y) || judge(x + n, y + n)) { Union(x, y + n); Union(x + n, y); }else { flag = false; } } if(i != 1) { out.println(); } out.println("Scenario #" + i + ":"); if(flag) { out.println("No suspicious bugs found!"); }else { out.println("Suspicious bugs found!"); } out.flush(); } } public static void Init(int n) { for (int i = 0; i <= n; i++) { par[i] = i; } } public static int find(int x) { if (x != par[x]) { par[x] = find(par[x]); } return par[x]; } public static void Union(int a, int b) { int x = find(a); int y = find(b); if (x != y) { par[x] = y; } } public static boolean judge(int x, int y) { x = find(x); y = find(y); if (x != y) { return true; } return false; } }
POJ_2524 Ubiquitous Religions
每次合併輸入的兩個數,最後找一個有幾個父親結點即可,(這裡我用的是set集合處理的)
package POJ; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StreamTokenizer; import java.util.HashSet; public class Poj_2524 { static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out)); public static int nextInt() throws IOException { in.nextToken(); return (int) in.nval; } public static String next() throws IOException { in.nextToken(); return (String) in.sval; } static int par[] = new int[50005]; public static void main(String[] args) throws IOException { int n, m, cas = 1; while(true) { n = nextInt(); m = nextInt(); if(n == 0 && m == 0) { break; } Init(n); int x, y; for(int i = 0; i < m; i++) { // m次詢問、 x = nextInt(); y = nextInt(); Union(x, y); } HashSet set = new HashSet(); for(int i = 1; i <= n; i++) { set.add(find(i)); } out.println("Case " + (cas++) + ": " + set.size()); out.flush(); } } public static void Init(int n) { for(int i = 0; i <= n; i++) { par[i] = i; } } public static int find(int x) { if(x != par[x]) { par[x] = find(par[x]); } return par[x]; } public static void Union(int a, int b) { int x = find(a); int y = find(b); if(x != y) { par[x] = y; } } }
POJ_1182 食物鏈
開三倍的陣列,x , x + n, x + 2n,分別表示,同類,被捕食,捕食者,如果輸入得是捕食關係的話那就合併,x , y + n和
x + n, y + 2n和 x + 2n , y 、 同類的話, 合併 x, y 和 x + n , y + n, 和 x + 2n, y + 2n,如果同之前的記錄有衝突,那麼假話++,
package POJ; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StreamTokenizer; public class Poj_1182 { static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out)); public static int nextInt() throws IOException { in.nextToken(); return (int) in.nval; } public static String next() throws IOException { in.nextToken(); return (String) in.sval; } static int par[] = new int[150005]; public static void main(String[] args) throws IOException { int n, k, ans = 0; int d, x, y; n = nextInt(); k = nextInt(); Init(n * 3); while (k-- > 0) { d = nextInt(); x = nextInt(); y = nextInt(); if (x > n || y > n) { ans++; continue; } if (d == 1) { // 第一種關係、同類 (不能出現捕食關係、與被捕食關係) if (same(x, y + n) || same(x, y + 2 * n)) { ans++; } else { Union(x, y); Union(x + n, y + n); Union(x + 2 * n, y + 2 * n); } } else { // 捕食關係 (不能出現同類,和反捕食的關係) if (same(x, y) || same(x, y + 2 * n)) { ans++; } else { Union(x, y + n); Union(x + n, y + 2 * n); Union(x + 2 * n, y); } } } out.println(ans); out.flush(); } public static void Init(int n) { for (int i = 0; i <= n; i++) { par[i] = i; } } public static int find(int x) { if (x != par[x]) { par[x] = find(par[x]); } return par[x]; } public static boolean same(int x, int y) { return find(x) == find(y); } public static void Union(int a, int b) { int x = find(a); int y = find(b); if (x != y) { par[x] = y; } } }
POJ_1861 Network
這裡用到了並查集,自定義排序,和求最小生成樹,
定義一個電纜類,儲存可連通的集線器的種類,以及該電纜的長度,然後定義一個比較器,對電纜的長度進行排序,
再利用kruskal演算法求最小生成樹,以及合併每次連通的兩個集線器,(遍歷所有的電纜不是連通的就合併,最後生成的就是最小生成樹)
package POJ;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;
public class Poj_1861 {
static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
public static int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
public static String next() throws IOException {
in.nextToken();
return (String) in.sval;
}
static Node node[] = new Node[15005];
static int par[] = new int[15005];
static boolean vis[] = new boolean[15005];
static int n, m, ans; // 記錄使用的最長的電纜的長度、
public static void main(String[] args) throws IOException {
n = nextInt();
m = nextInt();
Init(n);
int a, b, zz;
for (int i = 0; i < m; i++) {
a = nextInt();
b = nextInt();
zz = nextInt();
node[i] = new Node(a, b, zz);
}
/* out.println("看看輸入是否正確:");
for(int i = 0; i < m; i++) {
out.println(node[i].x + " " + node[i].y + " " + node[i].cost);
}
out.println("-----我是和諧的分界線-----");
out.println("看看輸入是否正確:");
for(int i = 0; i < m; i++) {
out.println(node[i].x + " " + node[i].y + " " + node[i].cost);
}
out.println("-----我是和諧的分界線-----"); */
Arrays.sort(node, 0, m);
ans = 0;
// 形成最小生成樹、
int num = kruskal();
out.println(ans);
out.println(num);
for(int i = 0; i < m; i++) {
if(vis[i]) {
out.println(node[i].x + " " + node[i].y);
}
}
out.flush();
}
public static int kruskal() {
int num = 0;
for(int i = 0; i < m; i++) {
Node tmp = node[i]; // 取出當前最小的電纜、
if(!same(tmp.x, tmp.y)) {
Union(tmp.x, tmp.y);
ans = Math.max(ans, tmp.cost); // 電纜的長度更新、
vis[i] = true; // 標記使用了、
num++; // 使用的電纜數 ++
}
}
return num;
}
public static void Init(int n) {
for (int i = 0; i <= n; i++) {
par[i] = i;
vis[i] = false;
}
}
public static int find(int a) {
if(par[a] != a) {
par[a] = find(par[a]);
}
return par[a];
}
public static boolean same(int a, int b) {
int x = find(a);
int y = find(b);
if (x == y) {
return true;
}
return false;
}
public static void Union(int a, int b) {
int x = find(a);
int y = find(b);
if (x != y) {
par[x] = y;
}
}
static class Node implements Comparable<Node> {
int x, y, cost;
Node(int x, int y, int dis) {
this.x = x;
this.y = y;
this.cost = dis;
}
Node() {
}
@Override
public int compareTo(Node o) {
return this.cost - o.cost;
}
}
}
POJ_1703 Find them,Catch them
這個可以用食物鏈的簡化版,同樣的是開兩倍的陣列,輸入D :x,y 不同幫派,那我們就合併 x , y + n 和 x + n, y 為同一幫派,當輸入A檢查時,判斷是否是同夥,不同夥,以及無法判斷,
package POJ;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class Poj_1703 {
static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
public static int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
public static String next() throws IOException {
in.nextToken();
return (String) in.sval;
}
static int par[] = new int[100005 * 2];
public static void main(String[] args) throws IOException {
int t = nextInt();
while(t-->0) {
int n , m;
n = nextInt();
m = nextInt();
Init(n * 2);
String s = "";
int a, b;
for(int i = 0; i < m; i++) {
s = next();
a = nextInt();
b = nextInt();
if(s.charAt(0) == 'A') { // 判斷是否同夥、、
if(same(a, b) || same(a + n, b + n)) { // 同夥
out.println("In the same gang.");
}else if(same(a, b + n) && same(a + n, b)) {
out.println("In different gangs.");
}else {
out.println("Not sure yet.");
}
out.flush();
}else { // 不同夥、、
Union(a, b + n);
Union(a + n, b);
}
}
}
}
public static void Init(int n) {
for (int i = 0; i <= n; i++) {
par[i] = i;
}
}
public static int find(int a) {
if (par[a] != a) {
par[a] = find(par[a]);
}
return par[a];
}
public static boolean same(int a, int b) {
int x = find(a);
int y = find(b);
if (x == y) {
return true;
}
return false;
}
public static void Union(int a, int b) {
int x = find(a);
int y = find(b);
if (x != y) {
par[x] = y;
}
}
}
POJ_2236 Wireless Network
當修復結點的時候,遍歷所有的情況、看看修復的電腦中,是否和該修復的電腦,在最大通訊範圍之內,如果是的話,就合併,但要注意的是,如果剛好在最大範圍上呢,這個double型別相等的情況雜比較,(*^__^*) (注意下標從1開始,好幾次空指標異常)
package POJ;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class Poj_2236 {
static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
public static int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
public static String next() throws IOException {
in.nextToken();
return (String) in.sval;
}
static int par[] = new int[1005];
static boolean repair[] = new boolean[1005];
static Node node[] = new Node[1005];
public static void main(String[] args) throws IOException {
int n, d;
n = nextInt(); // 計算機數量 、
d = nextInt(); // 最大的距離、、
int x, y;
Init(n);
for(int i = 1; i <= n; i++) { //輸入結點的座標、、
x = nextInt();
y = nextInt();
node[i] = new Node(x, y);
}
String s;
int q, p;
while(in.nextToken() != StreamTokenizer.TT_EOF) {
s = in.sval;
if(s.charAt(0) == 'O') { // 修復計算機、、
q = nextInt();
repair[q] = true;
for(int i = 1; i <= n; i++) { // 遍歷一遍、 周圍可以通訊的都合併起來、
if(i != q && repair[i] && distance(node[i], node[q]) <= (double)(d)) { // 不是自己, 修復好了, 而且距離小於最大的連通距離、
Union(i, q);
}
}
}else if(s.charAt(0) == 'S') {
q = nextInt();
p = nextInt();
if(same(q, p)) {
out.println("SUCCESS");
}else {
out.println("FAIL");
}
out.flush();
}
}
}
static class Node {
int x, y;
Node(int x, int y) {
this.x = x;
this.y = y;
}
Node() {
}
}
public static double distance(Node a, Node b) { // 計算出兩臺計算機 ,相距的距離、、
return Math.sqrt((double)((a.x - b.x) * (a.x - b.x)) + (double)((a.y - b.y) * (a.y - b.y)));
}
public static void Init(int n) {
for (int i = 0; i <= n; i++) {
par[i] = i;
repair[i] = false;
}
}
public static int find(int a) {
if (par[a] != a) {
par[a] = find(par[a]);
}
return par[a];
}
public static boolean same(int a, int b) {
int x = find(a);
int y = find(b);
if (x == y) {
return true;
}
return false;
}
public static void Union(int a, int b) {
int x = find(a);
int y = find(b);
if (x != y) {
par[x] = y;
}
}
}
Poj_2506:Freckles
這個題目輸入的是點的座標,然後讓我們連線(輸出最小的連線長度)、
這個有兩種方法、
1、Prim演算法:隨便以一個點為起點、計算出其他的點到該點的直線距離,選取最小的新增帶集合中,然後用這個點更新其他的距離,(選取最小的)
2:計算所有點距離其他點的座標,新增進入優先佇列中,(距離近的在前面),每次取出最小的,父節點相同?pass ,不同合併,燈集合的元素全部空了,或者合併的點到了n都可以結束,最後輸出。
思路一程式碼:
package POJ;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.math.BigDecimal;
public class Poj_2560_ {
static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
public static int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
public static String next() throws IOException {
in.nextToken();
return (String) in.sval;
}
static double mincost[] = new double[105];
static double dist[] = new double[105];
static boolean vis[] = new boolean[105];
static Node node[] = new Node[105];
public static void main(String[] args) throws IOException {
int n = nextInt();
double x , y;
for(int i = 0; i < n; i++) {
in.nextToken(); x = in.nval;
in.nextToken(); y = in.nval;
node[i] = new Node(x, y);
}
prim(n);
double ans = 0.0;
for(int i = 0; i < n - 1; i++) {
ans += mincost[i];
}
BigDecimal bd = new BigDecimal(ans).setScale(2, BigDecimal.ROUND_HALF_DOWN);
out.println(bd);
out.flush();
}
public static void prim(int n) {
for(int i = 0; i < n; i++) {
vis[i] = false;
if(i != 0) {
dist[i] = caldist(0, i);
}
}
dist[0] = 0;
vis[0] = true;
for(int i = 0; i < n; i++) {
double minD = Double.MAX_VALUE;
int id = 0;
for(int j = 1; j < n; j++) {
if(!vis[j] && dist[j] < minD) {
minD = dist[j];
id = j;
}
}
vis[id] = true;
mincost[i] = minD;
for(int j = 1; j < n; j++) {
if(!vis[j]) {
double zz = caldist(id, j);
dist[j] = Math.min(zz, dist[j]);
}
}
}
}
public static double caldist(int a, int b) {
double x = node[a].x - node[b].x;
double y = node[a].y - node[b].y;
return Math.sqrt(x * x + y * y);
}
public static void Init(int n) {
for (int i = 0; i < n; i++) {
node[i] = new Node();
}
}
static class Node {
double x, y;
Node(double x, double y) {
this.x = x;
this.y = y;
}
Node() {
}
}
}
思路二程式碼:
package POJ;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.math.BigDecimal;
import java.util.PriorityQueue;
public class Poj_2560 {
static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
public static int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
public static String next() throws IOException {
in.nextToken();
return (String) in.sval;
}
static Node node[] = new Node[105];
static int par[] = new int[105];
static PriorityQueue<Node> q = new PriorityQueue<Node>();
static int n;
static double sum;
public static void main(String[] args) throws IOException {
q.clear();
n = nextInt();
int x, y;
for (int i = 0; i < n; i++) {
x = nextInt();
y = nextInt();
node[i] = new Node(x, y); // 輸入的位置的座標,,
}
sum = 0;
Init(n);
while (!q.isEmpty()) {
Node tmp = q.poll();
if (!same(tmp.x, tmp.y)) {
sum += tmp.len;
Union(tmp.x, tmp.y);
}
}
BigDecimal bd = new BigDecimal(sum).setScale(2, BigDecimal.ROUND_HALF_DOWN);
out.println(bd);
out.flush();
}
public static boolean same(int a, int b) {
int x = find(a);
int y = find(b);
if (x == y) {
return true;
}
return false;
}
public static void Union(int a, int b) {
int x = find(a);
int y = find(b);
if (x != y) {
par[x] = y;
}
}
public static int find(int a) {
if (par[a] != a) {
par[a] = find(par[a]);
}
return par[a];
}
public static void Init(int n) {
for (int i = 0; i <= n; i++) {
par[i] = i;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == j) {
continue;
}
double dis = Math.sqrt((node[i].x - node[j].x) * (node[i].x - node[j].x)
+ (node[i].y - node[j].y) * (node[i].y - node[j].y));
q.add(new Node(i, j, dis));
}
}
}
public static class Node implements Comparable<Node> {
int x, y;
double len;
Node(int x, int y) {
this.x = x;
this.y = y;
}
Node(int x, int y, double len) {
this.x = x;
this.y = y;
this.len = len;
}
Node() {
}
@Override
public int compareTo(Node o) {
if (this.len < o.len) {
return -1;
} else if (this.len > o.len) {
return 1;
} else {
return 0;
}
}
}
}
Poj_1456 Supermarket
貪心求解,(貪心策略為,優先銷售利潤最大的、銷售時間,放在截止日期之前最近的未被佔用的一天)然後並查集合並
package POJ;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.PriorityQueue;
public class Poj_1456 {
static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
public static int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
public static String next() throws IOException {
in.nextToken();
return (String) in.sval;
}
static int par[] = new int[10005];
public static void main(String[] args) throws IOException {
while (in.nextToken() != StreamTokenizer.TT_EOF) {
int n = (int) in.nval;
PriorityQueue<Node> q = new PriorityQueue<Node>();
Init();
int x, y;
for (int i = 0; i < n; i++) {
x = nextInt();
y = nextInt();
q.add(new Node(x, y));
}
long sum = 0;
int z;
while (!q.isEmpty()) { // 優先佇列不為空, 彈出來、
Node zz = q.poll();
z = find(zz.d);
if(z > 0) {
sum += zz.p;
par[z] = z - 1;
}
}
out.println(sum);
out.flush();
}
}
public static void Init() {
for (int i = 0; i < 10005; i++) {
par[i] = i;
}
}
public static boolean same(int a, int b) {
int x = find(a);
int y = find(b);
if (x == y) {
return true;
}
return false;
}
public static void Union(int a, int b) {
int x = find(a);
int y = find(b);
if (x != y) {
par[x] = y;
}
}
public static int find(int a) {
if (par[a] != a) {
par[a] = find(par[a]);
}
return par[a];
}
static class Node implements Comparable<Node> {
int p, d;
public Node(int p, int d) {
this.p = p;
this.d = d;
}
public Node() {
}
@Override
public int compareTo(Node o) {
if (this.p == o.p) {
return this.d - o.d;
} else {
return o.p - this.p;
}
}
}
}