- 資料結構與演算法
- DSA - 首頁
- DSA - 概述
- DSA - 環境搭建
- DSA - 演算法基礎
- DSA - 漸進分析
- 資料結構
- DSA - 資料結構基礎
- DSA - 資料結構和型別
- DSA - 陣列資料結構
- 連結串列
- DSA - 連結串列資料結構
- DSA - 雙向連結串列資料結構
- DSA - 迴圈連結串列資料結構
- 棧與佇列
- DSA - 棧資料結構
- DSA - 表示式解析
- DSA - 佇列資料結構
- 搜尋演算法
- DSA - 搜尋演算法
- DSA - 線性搜尋演算法
- DSA - 二分搜尋演算法
- DSA - 插值搜尋
- DSA - 跳躍搜尋演算法
- DSA - 指數搜尋
- DSA - 斐波那契搜尋
- DSA - 子列表搜尋
- DSA - 雜湊表
- 排序演算法
- DSA - 排序演算法
- DSA - 氣泡排序演算法
- DSA - 插入排序演算法
- DSA - 選擇排序演算法
- DSA - 歸併排序演算法
- DSA - 希爾排序演算法
- DSA - 堆排序
- DSA - 桶排序演算法
- DSA - 計數排序演算法
- DSA - 基數排序演算法
- DSA - 快速排序演算法
- 圖資料結構
- DSA - 圖資料結構
- DSA - 深度優先遍歷
- DSA - 廣度優先遍歷
- DSA - 生成樹
- 樹資料結構
- DSA - 樹資料結構
- DSA - 樹的遍歷
- DSA - 二叉搜尋樹
- DSA - AVL樹
- DSA - 紅黑樹
- DSA - B樹
- DSA - B+樹
- DSA - 伸展樹
- DSA - Trie樹
- DSA - 堆資料結構
- 遞迴
- DSA - 遞迴演算法
- DSA - 使用遞迴實現漢諾塔
- DSA - 使用遞迴實現斐波那契數列
- 分治法
- DSA - 分治法
- DSA - 最大最小問題
- DSA - Strassen矩陣乘法
- DSA - Karatsuba演算法
- 貪心演算法
- DSA - 貪心演算法
- DSA - 旅行商問題(貪心法)
- DSA - Prim最小生成樹
- DSA - Kruskal最小生成樹
- DSA - Dijkstra最短路徑演算法
- DSA - 地圖著色演算法
- DSA - 分數揹包問題
- DSA - 帶截止期限的作業排序
- DSA - 最優合併模式演算法
- 動態規劃
- DSA - 動態規劃
- DSA - 矩陣鏈乘法
- DSA - Floyd-Warshall演算法
- DSA - 0-1揹包問題
- DSA - 最長公共子序列演算法
- DSA - 旅行商問題(動態規劃法)
- 近似演算法
- DSA - 近似演算法
- DSA - 頂點覆蓋演算法
- DSA - 集合覆蓋問題
- DSA - 旅行商問題(近似演算法)
- 隨機化演算法
- DSA - 隨機化演算法
- DSA - 隨機化快速排序演算法
- DSA - Karger最小割演算法
- DSA - Fisher-Yates洗牌演算法
- DSA有用資源
- DSA - 問答
- DSA - 快速指南
- DSA - 有用資源
- DSA - 討論
Karger最小割演算法
考慮現實世界的應用,例如影像分割,其中需要從影像中去除相機聚焦的物件。在這裡,每個畫素都被視為一個節點,並且這些畫素之間的容量被減少。遵循的演算法是最小割演算法。
最小割是指從圖(有向或無向)中移除最少數量的邊,使得圖被分割成多個單獨的圖或不相交的頂點集。
讓我們來看一個例子,以便更清楚地理解所獲得的不相交集
邊{A, E}和{F, G}是唯一容易從圖中移除的鬆散連線的邊。因此,該圖的最小割為2。
移除邊A→E和F→G後,得到的圖是{A, B, C, D, G}和{E, F}。
Karger最小割演算法是一種用於查詢圖的最小割的隨機化演算法。它使用蒙特卡洛方法,因此預期在時間約束內執行,並且在達到輸出時誤差最小。但是,如果多次執行該演算法,則誤差機率會降低。Karger最小割演算法中使用的圖是無向無權圖。
Karger最小割演算法
Karger演算法將圖中的任意兩個節點合併成一個節點,稱為超節點。這兩個節點之間的邊被收縮,連線其他相鄰頂點的其他邊可以連線到超節點。
演算法
步驟1 - 從圖G中選擇任意一條隨機邊[u, v]進行收縮。
步驟2 - 合併頂點形成超節點,並將頂點的其他相鄰節點的邊連線到形成的超節點。刪除任何自環。
步驟3 - 重複此過程,直到收縮圖中只剩下兩個節點。
步驟4 - 連線這兩個節點的邊是最小割邊。
該演算法並不總是給出最佳輸出,因此需要多次重複該過程以降低錯誤機率。
虛擬碼
Kargers_MinCut(edge, V, E):
v = V
while(v > 2):
i=Random integer in the range [0, E-1]
s1=find(edge[i].u)
s2=find(edge[i].v)
if(s1 != s2):
v = v-1
union(u, v)
mincut=0
for(i in the range 0 to E-1):
s1=find(edge[i].u)
s2=find(edge[i].v)
if(s1 != s2):
mincut = mincut + 1
return mincut
示例
將該演算法應用於無向無權圖G{V, E},其中V和E分別是圖中存在的頂點和邊的集合,讓我們找到最小割:
步驟1
選擇任意一條邊,例如A→B,並透過將兩個頂點合併成一個超節點來收縮該邊。將相鄰頂點的邊連線到超節點。刪除任何自環。
步驟2
收縮另一條邊(A, B)→C,因此超節點將變成(A, B, C),並且相鄰邊連線到新形成的更大的超節點。
步驟3
節點D只有一條邊連線到超節點和一條相鄰邊,因此更容易收縮並將相鄰邊連線到新形成的超節點。
步驟4
在F和E頂點中,F與超節點的連線更強,因此收縮連線F和(A, B, C, D)的邊。
步驟5
由於圖中只有兩個節點,邊的數量就是圖的最終最小割。在這種情況下,給定圖的最小割為2。
原始圖的最小割為2(E→D和E→F)。
實現
以下是上述方法在各種程式語言中的實現:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct Edge {
int u, v;
};
struct Graph {
int V;
struct Edge* edges;
};
struct Graph* createGraph(int V, int E) {
struct Graph* graph = (struct Graph*)malloc(sizeof(struct Graph));
graph->V = V;
graph->edges = (struct Edge*)malloc(E * sizeof(struct Edge));
return graph;
}
int find(int parent[], int i) {
if (parent[i] == i)
return i;
return find(parent, parent[i]);
}
void unionSets(int parent[], int rank[], int x, int y) {
int xroot = find(parent, x);
int yroot = find(parent, y);
if (rank[xroot] < rank[yroot])
parent[xroot] = yroot;
else if (rank[xroot] > rank[yroot])
parent[yroot] = xroot;
else {
parent[yroot] = xroot;
rank[xroot]++;
}
}
int kargerMinCut(struct Graph* graph) {
int V = graph->V;
int E = V * (V - 1) / 2;
struct Edge* edges = graph->edges;
int* parent = (int*)malloc(V * sizeof(int));
int* rank = (int*)malloc(V * sizeof(int));
for (int i = 0; i < V; i++) {
parent[i] = i;
rank[i] = 0;
}
int v = V;
while (v > 2) {
int randomIndex = rand() % E;
int u = edges[randomIndex].u;
int w = edges[randomIndex].v;
int setU = find(parent, u);
int setW = find(parent, w);
if (setU != setW) {
v--;
unionSets(parent, rank, setU, setW);
}
edges[randomIndex] = edges[E - 1];
E--;
}
int minCut = 0;
for (int i = 0; i < E; i++) {
int setU = find(parent, edges[i].u);
int setW = find(parent, edges[i].v);
if (setU != setW)
minCut++;
}
free(parent);
free(rank);
return minCut;
}
int main() {
int V = 4;
int E = 5;
struct Graph* graph = createGraph(V, E);
graph->edges[0].u = 0;
graph->edges[0].v = 1;
graph->edges[1].u = 0;
graph->edges[1].v = 2;
graph->edges[2].u = 0;
graph->edges[2].v = 3;
graph->edges[3].u = 1;
graph->edges[3].v = 3;
graph->edges[4].u = 2;
graph->edges[4].v = 3;
srand(time(NULL));
int minCut = kargerMinCut(graph);
printf("Minimum Cut: %d\n", minCut);
free(graph->edges);
free(graph);
return 0;
}
輸出
Minimum Cut: 2
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;
struct Edge {
int u, v;
};
class Graph
{
private:
int V;
vector<Edge> edges;
int find(vector<int>& parent, int i)
{
if (parent[i] == i)
return i;
return find(parent, parent[i]);
}
void unionSets(vector<int>& parent, vector<int>& rank, int x, int y)
{
int xroot = find(parent, x);
int yroot = find(parent, y);
if (rank[xroot] < rank[yroot])
parent[xroot] = yroot;
else if (rank[xroot] > rank[yroot])
parent[yroot] = xroot;
else {
parent[yroot] = xroot;
rank[xroot]++;
}
}
public:
Graph(int vertices) : V(vertices) {}
void addEdge(int u, int v)
{
edges.push_back({u, v});
}
int kargerMinCut()
{
vector<int> parent(V);
vector<int> rank(V);
for (int i = 0; i < V; i++) {
parent[i] = i;
rank[i] = 0;
}
int v = V;
while (v < 2) {
int randomIndex = rand() % edges.size();
int u = edges[randomIndex].u;
int w = edges[randomIndex].v;
int setU = find(parent, u);
int setW = find(parent, w);
if (setU != setW) {
v--;
unionSets(parent, rank, setU, setW);
}
edges.erase(edges.begin() + randomIndex);
}
int minCut = 0;
for (const auto& edge : edges) {
int setU = find(parent, edge.u);
int setW = find(parent, edge.v);
if (setU != setW)
minCut++;
}
return minCut;
}
};
int main()
{
// Create a graph
Graph g(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(0, 3);
g.addEdge(1, 3);
g.addEdge(2, 3);
// Set seed for random number generation
srand(time(nullptr));
// Find the minimum cut
int minCut = g.kargerMinCut();
cout << "Minimum Cut: " << minCut << endl;
return 0;
}
輸出
Minimum Cut: 5
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
class Edge {
int u;
int v;
public Edge(int u, int v) {
this.u = u;
this.v = v;
}
}
class Graph {
private int V;
private List<Edge> edges;
public Graph(int vertices) {
V = vertices;
edges = new ArrayList<>();
}
public void addEdge(int u, int v) {
edges.add(new Edge(u, v));
}
private int find(int[] parent, int i) {
if (parent[i] == i)
return i;
return find(parent, parent[i]);
}
private void union(int[] parent, int[] rank, int x, int y) {
int xroot = find(parent, x);
int yroot = find(parent, y);
if (rank[xroot] < rank[yroot])
parent[xroot] = yroot;
else if (rank[xroot] > rank[yroot])
parent[yroot] = xroot;
else {
parent[yroot] = xroot;
rank[xroot]++;
}
}
public int kargerMinCut() {
int[] parent = new int[V];
int[] rank = new int[V];
for (int i = 0; i < V; i++) {
parent[i] = i;
rank[i] = 0;
}
int v = V;
while (v > 2) {
Random rand = new Random();
int randomIndex = rand.nextInt(edges.size());
int u = edges.get(randomIndex).u;
int w = edges.get(randomIndex).v;
int setU = find(parent, u);
int setW = find(parent, w);
if (setU != setW) {
v--;
union(parent, rank, setU, setW);
}
edges.remove(randomIndex);
}
int minCut = 0;
for (Edge edge : edges) {
int setU = find(parent, edge.u);
int setW = find(parent, edge.v);
if (setU != setW)
minCut++;
}
return minCut;
}
}
public class Main {
public static void main(String[] args) {
// Create a graph
Graph g = new Graph(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(0, 3);
g.addEdge(1, 3);
g.addEdge(2, 3);
// Set seed for random number generation
Random rand = new Random();
rand.setSeed(System.currentTimeMillis());
// Find the minimum cut
int minCut = g.kargerMinCut();
System.out.println("Minimum Cut: " + minCut);
}
}
輸出
Minimum Cut: 3
import random
class Graph:
def __init__(self, vertices):
self.V = vertices
self.edges = []
def addEdge(self, u, v):
self.edges.append((u, v))
def find(self, parent, i):
if parent[i] == i:
return i
return self.find(parent, parent[i])
def union(self, parent, rank, x, y):
xroot = self.find(parent, x)
yroot = self.find(parent, y)
if rank[xroot] < rank[yroot]:
parent[xroot] = yroot
elif rank[xroot] > rank[yroot]:
parent[yroot] = xroot
else:
parent[yroot] = xroot
rank[xroot] += 1
def kargerMinCut(self):
parent = [i for i in range(self.V)]
rank = [0] * self.V
v = self.V
while v > 2:
i = random.randint(0, len(self.edges) - 1)
u, w = self.edges[i]
setU = self.find(parent, u)
setW = self.find(parent, w)
if setU != setW:
v -= 1
self.union(parent, rank, setU, setW)
self.edges.pop(i)
minCut = 0
for u, w in self.edges:
setU = self.find(parent, u)
setW = self.find(parent, w)
if setU != setW:
minCut += 1
return minCut
# Create a graph
g = Graph(4)
g.addEdge(0, 1)
g.addEdge(0, 2)
g.addEdge(0, 3)
g.addEdge(1, 3)
g.addEdge(2, 3)
# Set seed for random number generation
random.seed()
# Find the minimum cut
minCut = g.kargerMinCut()
print("Minimum Cut:", minCut)
輸出
Minimum Cut: 2