老实说看完并查集再看最小生成树已经没什么意思了,在kuangbin大佬的训练题中没有什么特别有难度的,除了次小生成树。先挂两个板子。(最小生成树的学习可以借鉴《图论与集合》,或者各位大佬的博客)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <limits>
#include <vector>
#include <sstream>
#define ll long long
using namespace std;
const int maxn = 10000 + 10;
const int maxm = 1000000 + 10;
const int inf = 0x3f3f3f3f;
int fa[maxn];
int rnk[maxn];
int n, m;
struct node {
int a, b;
int c;
friend bool operator < (node x, node y) {
return x.c < y.c;
}
}q[maxn];
void init() {
for(int i = 0; i <= n; i++) {
fa[i] = i;
rnk[i] = 0;
}
}
int getf(int x) {
if(x != fa[x]) {
fa[x] = getf(fa[x]);
}
return fa[x];
}
void unions(int x, int y) {
x = getf(x);
y = getf(y);
if(x == y) return;
if(rnk[x] < rnk[y]) {
fa[x] = y;
}
else {
fa[y] = x;
if(rnk[x] == rnk[y]) rnk[x]++;
}
}
bool same(int x, int y) {
return getf(x) == getf(y);
}
int kruskal(int n, int m) {
init();
sort(q + 1, q + 1 + m);
int ans = 0;
int nedge = 0;
for(int i = 1; i <= m && nedge != n - 1; i++) {
if(getf(q[i].a) != getf(q[i].b)) {
unions(q[i].a, q[i].b);
ans += q[i].c;
nedge++;
}
}
if(nedge < n - 1) ans = -1;
return ans;
}
int main()
{
int T, kcase = 0;
while(scanf("%d", &n) && n) {
scanf("%d", &m);
for(int i = 1; i <= m; i++) {
scanf("%d %d %d", &q[i].a, &q[i].b, &q[i].c);
}
int ans = kruskal(n, m);
printf("%d\n", ans);
}
return 0;
}
次小生成树:
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <cstdio>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 10001;
int n, m;
int num;
int p[maxn];
int maxx[101][101];
struct Edge //原始图
{
int from;
int to;
int w;
bool flag;
friend bool operator < (Edge x, Edge y) {
return x.w < y.w;
}
}e[maxn];
struct Tree //最小生成树
{
int to;
int w;
int next;
}tree[202];
int index[101];
struct Node //生成树的结点
{
int seq; //结点编号
int maxx; //从某个点到它的路径中的最大边的长度
};
void makeSet()
{
for(int i = 0; i <= n; i++)
{
p[i] = i;
}
}
int findSet(int x)
{
if(x != p[x])
p[x] = findSet(p[x]);
return p[x];
}
void addEdge(int from, int to, int w)
{
tree[num].to = to;
tree[num].w = w;
tree[num].next = index[from];
index[from] = num++;
}
int kruscal()
{
int x, y;
int edgeNum = 0;
int result = 0;
makeSet();
sort(e, e + m);
for(int i = 0; i < m; i++) {
x = findSet(e[i].from);
y = findSet(e[i].to);
if(x != y) {
edgeNum++;
addEdge(e[i].from,e[i].to,e[i].w);
addEdge(e[i].to,e[i].from,e[i].w);
e[i].flag = true;
p[x] = y;
result += e[i].w;
}
}
return edgeNum == n - 1 ? result : -1;
}
void bfs(int p)
{
bool used[101];
memset(used, 0, sizeof(used));
queue<Node> que;
Node now, adj;
now.maxx = 0;
now.seq = p;
que.push(now);
used[p] = true;
while(!que.empty()) {
Node q = que.front();
que.pop();
for(int i = index[q.seq]; i != -1; i = tree[i].next) {
adj.seq = tree[i].to;
adj.maxx = tree[i].w;
if(!used[adj.seq]) {
if(q.maxx > adj.maxx)
adj.maxx = q.maxx;
maxx[p][adj.seq] = adj.maxx;
used[adj.seq] = true;
que.push(adj);
}
}
}
}
void second_MST()
{
int mst = kruscal();
for(int i = 1; i <= n; i++)
bfs(i);
int smst = inf;
for(int i = 0; i < m; i++) {
if(!e[i].flag) {
if(mst + e[i].w - maxx[e[i].from][e[i].to] < smst)
smst = mst + e[i].w - maxx[e[i].from][e[i].to];
}
}
if(smst == mst)
printf("Not Unique!\n");
else
printf("%d\n", mst);
}
int main()
{
int cases;
int a, b, w;
scanf("%d", &cases);
while(cases--) {
scanf("%d %d", &n, &m);
for(int i = 0; i < m; i++) {
scanf("%d %d %d", &e[i].from, &e[i].to, &e[i].w);
e[i].flag = false;
}
num = 0;
memset(index, -1, sizeof(index));
second_MST();
}
return 0;
}