最小生成树
例题
https://www.luogu.com.cn/problem/P3366
方法一:prim算法
#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> using namespace std; #define maxn 5001 #define inf 0x3f3f3f3f int n, m; int edges[maxn][maxn]; int ecost[maxn]; int prim() { int allcount = 0; ecost[1] = 0;//不使用vis数组来标记是否访问过,而是使用ecost【】=0表示该节点已经加入到了最小生成树中 for (int i = 2; i <= n; i++) { ecost[i] = edges[1][i]; } int mins = inf, mini = -1; for (int i = 2; i <= n; i++) { mins = inf, mini = -1; for (int j = 1; j <= n; j++) { if (ecost[j] != 0 && ecost[j] < mins) { mins = ecost[j]; mini = j; } } if (mini == -1)return -1; allcount += ecost[mini]; ecost[mini] = 0; for (int j= 2; j <= n; j++) { if (ecost[j]!=0 && edges[mini][j] < ecost[j]) ecost[j] =edges[mini][j] ; } } return allcount; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) edges[i][j] = inf; for (int i = 0; i < m; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); if (edges[a][b] != 0)//这里看输入实例发现存在重边(1 2 300 ;1 2 500; 2 1 700 应该取300) { if(c<edges[a][b]) edges[a][b] = edges[b][a] = c; } else edges[a][b] = edges[b][a] = c; if (a == b) edges[a][b] = edges[b][a] = 0; } int answer = prim(); if (answer == -1)printf("orz"); else printf("%d", answer); }
注意事项:要在输入的时候提前处理重边的情况 注意edge数组要进行初始化为INF !!!!!
使用链式前向星:
#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> using namespace std; #define maxn 5001 #define maxm 200005 #define inf 0x3f3f3f3f int n, m,cnt=0; int ecost[maxn],head[maxn]; struct edge { int to; int dis; int next; }e[maxm*2]; void addedge(int u, int v, int w) { cnt++; e[cnt].to = v; e[cnt].dis = w; e[cnt].next = head[u]; head[u] = cnt; } int prim() { int allcount = 0; for (int i = 1; i <= n; i++) { ecost[i] = inf; } ecost[1] =0; for (int i = head[1]; i; i = e[i].next) { int y = e[i].to; ecost[y] = min(ecost[y],e[i].dis);//这里进行了去除重边的判断 } int mins = inf, mini = -1; for (int i = 2; i <= n; i++) { mins = inf, mini = -1; for (int j = 1; j <= n; j++) { if (ecost[j] != 0 && ecost[j] < mins) { mins = ecost[j]; mini = j; } } if (mini == -1)return -1; allcount += ecost[mini]; ecost[mini] = 0; for (int i = head[mini]; i; i = e[i].next) { int y = e[i].to; if (ecost[y] != 0 && ecost[y] > e[i].dis) ecost[y] = e[i].dis; } } return allcount; } int main() { scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); addedge(a, b, c); addedge(b, a, c); } int answer = prim(); if (answer == -1)printf("orz"); else printf("%d", answer); }
法二:kruskal算法
#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> using namespace std; #define maxn 5001 #define maxm 200005 #define inf 0x3f3f3f3f int n, m, cnt = 0,allcount=0; int ecost[maxn], father[maxn]; struct edge { int to; int dis; int from; }e[maxm]; bool cmp(struct edge&a, struct edge &b) { return a.dis < b.dis; } int find(int x) { if (x == father[x])return x; return father[x] = find(father[x]); } int kruskal() { sort(e, e + m, cmp); for (int i = 0; i <m; i++)//一共m条边。一条一条判断 { int tempa, tempb; tempa = find(e[i].from); tempb = find(e[i].to); if (tempa == tempb)continue; allcount += e[i].dis; father[tempa] = tempb; } return allcount; } int main() { scanf("%d%d", &n, &m); for (int i = 0; i <= n; i++) father[i] = i; for (int i = 1; i <=m; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); e[cnt].from = a; e[cnt].to = b; e[cnt].dis = c; cnt++; } int answer = kruskal(); if (answer == -1)printf("orz"); else printf("%d", answer); }