HDU 1233 还是畅通工程 解题报告
解题思路:最小生成树基本题,我两种方法都写了一下,看注释吧。
1.prim算法。这个算法核心思想就是从第一个点开始建树,每次找离树最近的点加入树。
#include<iostream>
#include<math.h>
#include<iomanip>
#include<algorithm>
#include<iostream>
#include<math.h>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<map>
#include<stack>
#include<stdio.h>
#include<cstdio>
#include<stdlib.h>
#include<fstream>
#include<iomanip>
#include<vector>
#pragma warning(disable:4996)
#define INF 0x3f3f3f3f
#define ll long long
#define PI acos(-1.0)
const int N = 200010;
const int maxn = 1e5+10;
using namespace std;
int d[105];//放每个点到树的最短距离
int visit[105];
int edge[105][105];
void prim(int n)
{
for (int i = 1; i <= n; i++)//一开始的树就是一个点
d[i] = edge[1][i];
int ans = 0;
d[1] = 0;
visit[1] = 1;
for (int i = 2; i <= n; i++)//进行n-1次操作,i只是计数用
{
int u = INF;
int pos;
for (int j = 1; j <= n; j++)
{
if (!visit[j] && u > d[j])//每次都在没用过的点中找与已建成的树距离最短的点
{
u = d[j];
pos = j;
}
}
visit[pos] = 1;
ans += u;
for (int j = 1; j <= n; j++)
{
if (!visit[j] && d[j] > edge[pos][j])
{
d[j] = edge[pos][j];//更新没用过的点到树的最短距离
}
}
}
printf("%d\n", ans);
}
int main()
{
int n;
while (~scanf("%d", &n) && n)
{
memset(visit, 0, sizeof(visit));
int m = (n - 1) * n / 2;
int u, v, w;
while (m--)
{
scanf("%d%d%d", &u, &v, &w);
edge[u][v] = edge[v][u] = w;//注意是无向图
}
prim(n);
}
return 0;
}
2.kruskal算法。这个算法的核心思想在于每次连接森林里最近的两个未连通的点,最后成树。
#include<iostream>
#include<math.h>
#include<iomanip>
#include<algorithm>
#include<iostream>
#include<math.h>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<map>
#include<stack>
#include<stdio.h>
#include<cstdio>
#include<stdlib.h>
#include<fstream>
#include<iomanip>
#include<vector>
#pragma warning(disable:4996)
#define INF 0x3f3f3f3f
#define ll long long
#define PI acos(-1.0)
const int N = 200010;
const int maxn = 1e5+10;
using namespace std;
int father[maxn];
struct node {
int u, v, val;
}edge[maxn];
bool cmp(node a, node b)
{
return a.val < b.val;
}
int find(int x)
{
if (x == father[x])
return x;
else
return father[x] = find(father[x]);
}
void kruskal(int n, int m)
{
sort(edge + 1, edge + m + 1, cmp);
for (int i = 1; i <= n; i++)
father[i] = i;
int ans = 0;
for (int i = 1; i <= m; i++)
{
int a = find(edge[i].u);
int b = find(edge[i].v);
if (a != b)//用并查集的方式判断两个点是否连通
{
father[a]=b;
ans += edge[i].val;
}
}
printf("%d\n", ans);
}
int main()
{
int n;
while (~scanf("%d", &n) && n)
{
int m = (n - 1) * n / 2;
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].val);
}
kruskal(n, m);
}
return 0;
}