title: poj-1251-最小生成树
date: 2018-11-20 16:38:14
tags:
- acm
- 刷题
categories: ACM-最小生成树
概述
前段时间数据结构的课上提到了了最小生成树,,暑假的集训虽然再学并查集的时候看过一些,,但是之后好久没再用过,,早就忘记了,,,今天抽时间看了看,,把最小生成树的两个主要算法 prim 和 kruskal了解了一下,,,做几道题,,把自己的模板弄出来
分析
这两个算法很简单,,,看几遍就可以去敲去了,,,
放几个别人的博客,,防止以后忘记了能快速回想起来
还有一个
prim算法主要的思路是将最小生成树慢慢的变大,,,
kruskal算法主要是利用并查集将多个树也就是森林慢慢的合并成最后的树
模板代码
做了一道模板题,,题意就是对给定的一个图,,去掉一些边,,求花费最小的方案,,,其实就是权值和最小的那一种,,
prim方法:
#include
#include
#include
#include
#include
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 30;
int mp[maxn][maxn];
bool vis[maxn];
int dis[maxn];
int n , m;
int prim()
{
int sum = 0;
memset(vis , false , sizeof vis);
vis[1] = true;
for(int i = 1; i <= n; ++i)
dis[i] = mp[1][i];
for(int i = 1; i < n; ++i)
{
int m = inf;
int p = -1;
//从所有的为加入最小生成树集合的点集里找到一个边权最小的
for(int j = 1; j <= n; ++j)
if(!vis[j] && dis[j] < m)
{
m = dis[j];
p = j;
}
if(m == inf) return -1;
sum += m;
vis[p] = true;
//更新加入这个点之后能够到达其他点的值
for(int j = 1; j <= n; ++j)
if(!vis[j] && dis[j] > mp[p][j])
dis[j] = mp[p][j];
}
return sum;
}
int main()
{
while(scanf("%d" , &n) && n)
{
char c1 , c2;
int m1 , m2;
memset(mp , inf , sizeof mp);
for(int i = 1; i <= n; ++i)
mp[i][i] = 0;
for(int i = 1; i <= n - 1; ++i)
{
scanf(" %c%d" , &c1 , &m1);
for(int j = 1; j <= m1; ++j)
{
scanf(" %c%d" , &c2 , &m2);
mp[c1 - 'A' + 1][c2 - 'A' + 1] = m2;
mp[c2 - 'A' + 1][c1 - 'A' + 1] = m2;
}
}
printf("%d\n" , prim());
}
return 0;
}
kruskal方法:
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 200;
const int inf = 0x3f3f3f3f;
int father[maxn];
int n , m;
struct edge
{
int u , v , w;
bool operator < (const edge &r) const
{
return w < r.w;
}
}edge[maxn];
int tot;
void addedge(int _u , int _v , int _w)
{
edge[tot].u = _u;
edge[tot].v = _v;
edge[tot++].w = _w;
}
int find(int x)
{
if(x == father[x]) return x;
else return father[x] = find(father[x]);
}
int kruskal()
{
for(int i = 1; i <= n; ++i)
father[i] = i;
sort(edge , edge + tot);
int cnt = 0;
int sum = 0;
for(int i = 0; i < tot; ++i)
{
int t1 = find(edge[i].u);
int t2 = find(edge[i].v);
//u , v如果不在一个森林中就合并
if(t1 != t2)
{
sum += edge[i].w;
father[t1] = t2;
++cnt;
}
if(cnt == n - 1) break;
}
if(cnt < n - 1) return -1;
else return sum;
}
int main()
{
while(scanf("%d" , &n) && n)
{
char c1 , c2;
int m1 , m2;
tot = 0;
for(int i = 1; i < n; ++i)
{
scanf(" %c%d" , &c1 , &m1);
for(int j = 1; j <= m1; ++j)
{
scanf(" %c%d" , &c2 , &m2);
addedge(c1 - 'A' + 1 , c2 - 'A' + 1 , m2);
addedge(c2 - 'A' + 1 , c1 - 'A' + 1 , m2);
}
}
printf("%d\n" , kruskal());
}
}
(end)