poj-1251-最小生成树

概述

前段时间数据结构的课上提到了了最小生成树,,暑假的集训虽然再学并查集的时候看过一些,,但是之后好久没再用过,,早就忘记了,,,今天抽时间看了看,,把最小生成树的两个主要算法 primkruskal了解了一下,,,做几道题,,把自己的模板弄出来

分析

这两个算法很简单,,,看几遍就可以去敲去了,,,

放几个别人的博客,,防止以后忘记了能快速回想起来
还有一个

prim算法主要的思路是将最小生成树慢慢的变大,,,
kruskal算法主要是利用并查集将多个树也就是森林慢慢的合并成最后的树

模板代码

做了一道模板题,,题意就是对给定的一个图,,去掉一些边,,求花费最小的方案,,,其实就是权值和最小的那一种,,

prim方法:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string.h>
#include <algorithm>

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 <iostream>
#include <cstdio>
#include <cstdlib>
#include <string.h>
#include <algorithm>

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)

posted @ 2018-11-20 16:55  31415926535x  阅读(328)  评论(0编辑  收藏  举报