MST

MST最主流的方法就两个,Kruskal和Prime,先说说算法思想吧。
Kruskal就是不断找不会出现回路的MST,一条一条边的找,需要用到并查集和最小堆的知识。
Prime就是:
1、将所有的点分为找过的和没有找过的两个集合T和T'
2、抽象出从T集合到T'集合的点相互之间只要有边,就有一个带全路径
3、将任意一个点放入T集合
4、将T集合中的点到T'集合中的点连线所有边中最短的边找出,对应在T'中集合的点v加入到T集合中
5、重复进行4,直至所有点全部进入T集合(前提是有MST)
然后在蓝皮上发现还有提到一个想法,叫Boruvka,然后离散课本上貌似也有类似的想法。因为这次时间紧迫,这些内容我会在将来补充。先就Kruskal和Prime进行深入的挖掘吧。下面是具体题目。

poj1861/zoj1542
确切的说这不是一道很纯粹的MST,只是MST正好可以解决。因为由题意我们可以发现要生成的那棵树所有边的最大值最小完全可以有很多的可能,比如一个权值都是1的树,而MST正好能够保证这一条性质,所以想清楚了这点就是一道裸题。MST的直径。

poj1251/zoj1406
裸题一道。MST的路径和。

poj2031/zoj11718
一道不是那么裸的裸题。只需要转换一下:空间站之间的距离如何计算:三位坐标的距离大于二者的半径之和需要走廊,否则就不需要走廊。MST的路径和。

poj1287/zoj1372
裸裸裸。。。感觉切裸题太伤神、伤身了。。。╮(╯▽╰)╭
MST的路径和。

poj2421
稍微转一下脑子就行。
有些路已经生成了,直接放到UFset就行,MST的路径和。

zoj1586
裸题一道。有些小trick,注意就行,MST的路径和。

poj1789/zoj2158
还是裸题,纯粹就是为了看看模板的稳定性了。不过不得不提一下,刚刚在poj上提交的时候发现MLE了,用的是PriorityQueue+数组模拟的那个方法,然后贴了一个傻瓜版的基础方法,邻接矩阵就华丽丽的过了。这也表示有时候虽然有些方法的确很优雅,但是在MLE这种让人蛋疼的情况下。。。还是忍忍吧。。。O(∩_∩)O哈!MST的路径和。

贴一下模板:
kruskal:
static class kruskal {
int n, index, parent[], rank[];
PriorityQueue que = new PriorityQueue();

kruskal(int n) {
this.n = n;
this.index = 0;
parent = new int[n + 1];
for (int i = 1; i <= n; i++)
parent[i] = i;
rank = new int[n + 1];
Arrays.fill(rank, 1);
}

void addEdge(int u, int v, int val) {
que.add(new node(u, v, val));
}

int find(int i) {
if (parent[i] != i)
parent[i] = find(parent[i]);
return parent[i];
}

void union(int ra, int rb) {
if (rank[ra] > rank[rb])
parent[rb] = ra;
else {
if (rank[ra] == rank[rb])
rank[rb]++;
parent[ra] = rb;
}
}

void solve() {
node temp;
int ra, rb;
//
int sum = 0;

while (!que.isEmpty()) {
temp = que.poll();
ra = find(temp.u);
rb = find(temp.v);
if (ra != rb) {
union(ra, rb);
//
sum += temp.val;
}
}
//
out.println(sum);
}
}

static class node implements Comparable {
int u, v;
int val;
node(int u, int v, int val) {
this.u = u;
this.v = v;
this.val = val;
}

public int compareTo(node o) {
if (this.val < o.val)
return -1;
else if (this.val > o.val)
return 1;
return 0;
}
}

Prime:
邻接矩阵实现:
static class Prime {
int n, inf = Integer.MAX_VALUE;
int adj[][];
Prime(int n) {
this.n = n;
adj = new int[n + 1][n + 1];
for (int i = 1; i <= n; i++)
Arrays.fill(adj[i], inf);
}
void addEdge(int u, int v, int val) {
adj[u][v] = val;
}
boolean solve(int v0) {
int dist[] = new int[n + 1];
int near[] = new int[n + 1];

for (int i = 1; i <= n; i++) {
dist[i] = adj[v0][i];
near[i] = v0;
}
dist[v0] = -1;
int min, sum = 0;
int u;
for (int time = 1; time < n; time++) {
min = Integer.MAX_VALUE;
u = v0;
for (int i = 1; i <= n; i++) {
if (dist[i] != -1 && dist[i] < min) {
min = dist[i];
u = i;
}
}

for (int i = 1; i <= n; i++) {
if (dist[i] == -1) {
if (adj[i][u] == min && near[u] != i) {
return false;
}
}
}
dist[u] = -1;
sum += min;

for (int i = 1; i <= n; i++) {
if (dist[i] > adj[u][i]) {
dist[i] = adj[u][i];
near[i] = u;
}
}
}
out.println(sum);
return true;
}
}
数组模拟邻接链表:
static class Prime {
int n, m, index;
int head[];
node edge[];

Prime(int n, int m) {
this.n = n;
this.m = m;
index = 0;
head = new int[n + 1];
Arrays.fill(head, -1);
edge = new node[m + 1];
}

void addEdge(int u, int v, int val) {
index++;
edge[index] = new node();
edge[index].next = head[u];
edge[index].v = v;
edge[index].val = val;
head[u] = index;
}

int solve(int v0) {
int dist[] = new int[n + 1];
int used[] = new int[n + 1];

used[v0] = 1;
for (int i = head[v0]; i != -1; i = edge[i].next) 
dist[edge[i].v] = edge[i].val;

int min, u, sum = 0;
for (int time = 1; time < n; time++) {
min = Integer.MAX_VALUE;
u = v0;

for (int i = 1; i <= n; i++) {
if (used[i] == 0 && dist[i] < min) {
min = dist[i];
u = i;
}
}

sum += min;
dist[u] = min;
used[u] = 1;

for (int i = head[u]; i != -1; i = edge[i].next) {
if (used[edge[i].v] == 0 && dist[edge[i].v] > edge[i].val)
dist[edge[i].v] = edge[i].val;
}
}
return sum;
}
}

static class node {
int u, v, next, val;

node() {
this.next = -1;
}
}
数组模拟邻接链表+优先队列:
static class Prime {
int n, m, index;
int head[];
node edge[];
PriorityQueue queue = new PriorityQueue();

Prime(int n, int m) {
this.n = n;
this.m = m;
index = 0;
head = new int[n + 1];
Arrays.fill(head, -1);
edge = new node[m + 1];
}

void addEdge(int u, int v, int val) {
index++;
edge[index] = new node();
edge[index].next = head[u];
edge[index].v = v;
edge[index].val = val;
head[u] = index;
}

int solve(int v0) {
int used[] = new int[n + 1];

used[v0] = 1;
for (int i = head[v0]; i != -1; i = edge[i].next)
queue.add(edge[i]);

int u, sum = 0;
node temp;

while (!queue.isEmpty()) {
temp = queue.poll();
u = temp.v;
if (used[u] == 1)
continue;
sum += temp.val;
used[u] = 1;
for (int i = head[u]; i != -1; i = edge[i].next) {
queue.add(edge[i]);
}
}
return sum;
}
}

static class node implements Comparable {
int u, v, next, val;

node() {
this.next = -1;
}

public int compareTo(node o) {
if (this.val < o.val)
return -1;
else if (this.val > o.val)
return 1;
return 0;
}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值