最小生成树 算法

nyoj 38 http://acm.nyist.net/JudgeOnline/problem.php?pid=38


prim  克鲁斯卡尔  两个算法

首先说说 克鲁斯卡尔算法,按照边的从小到大排序之后,利用并查集的思想,不断并。直到并出n-1条边。

 
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<algorithm>
#include<queue>
#include<cmath>

using namespace std;
typedef long long int LL;
const int INF=2e9+1e8;
const double eps=1e-8;
const int MM=500+5;


struct Edge
{
    int s,t,val;
};

Edge edge[MM*MM/2];
int m,n;
int pre[MM];
void init_pre()
{
    for(int i=0; i<=n; i++)
        pre[i]=i;
}

bool cmp(Edge a,Edge b)
{
    return a.val<b.val;
}
int getfa(int x)
{
    return pre[x]==x?x:pre[x]=getfa(pre[x]);
}
bool merges(int x,int y)
{
    int fx=getfa(x),fy=getfa(y);
    if(fx==fy) return false;
    else
    {
        pre[fx]=fy;
        return true;
    }
}
int Kruskal()
{
    sort(edge+1,edge+1+m,cmp);
    int tot=0;
    for(int i=1; i<=m; i++)
    {
        if(merges(edge[i].s,edge[i].t))
        {
            tot+=edge[i].val;
        }
    }
    return tot;
}
int main()
{
    int ncase;
    scanf("%d",&ncase);
    while(ncase--)
    {
        scanf("%d%d",&n,&m);
        init_pre();
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d%d",&edge[i].s,&edge[i].t,&edge[i].val);
        }
        int minn=INF;
        for(int i=1; i<=n; i++)
        {
            int temp;
            scanf("%d",&temp);
            minn=min(temp,minn);
        }
        printf("%d\n",Kruskal()+minn);
    }
    return 0;
}
        



prim

1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
3).重复下列操作,直到Vnew = V:
a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
4).输出:使用集合Vnew和Enew来描述所得到的最小生成树

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
const int maxn=505;
const int INF=0x3f3f3f3f;
int map[maxn][maxn];
int dis[maxn];
int vis[maxn];
int N;//N组测试数据
int V;//点的数量
int E;//边的数量
int min_num;//最小外接花费
void init()
{
    scanf("%d%d",&V,&E);
    for(int i=0; i<=V; i++)//初始化图
        for(int j=0; j<=V; j++)
            i==j?map[i][j]=0:map[i][j]=INF;
    while(E--)//建图
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        map[a][b]=c;//无向图
        map[b][a]=c;
    }
    min_num=INF;
    for(int i=1; i<=V; i++)
    {
        int x;
        scanf("%d",&x);
        min_num=min(min_num,x);//生成树连接到外界的最小花费
        dis[i]=map[i][1];//从1开始构造最小生成树
    }
    memset(vis,0,sizeof(vis));
    vis[1]=1;//0代表是外界
}
void Prim()
{
    int min_cost=0;//初始化最小花费
    for(int i=1; i<V; i++)
    {
        int minn=INF;
        int point_minn;
        for(int j=1; j<=V; j++)
            if(vis[j]==0&&minn>dis[j])
            {
                point_minn=j;
                minn=dis[j];
            }
        if(minn==INF)
            break;
        min_cost+=dis[point_minn];
        vis[point_minn]=1;
        for(int j=1; j<=V; j++)
            if(vis[j]==0&&dis[j]>map[point_minn][j])
                dis[j]=map[point_minn][j];
    }
    printf("%d\n",min_cost+min_num);
}
int main()
{
    scanf("%d",&N);
    while(N--)
    {
        init();
        Prim();
    }
    return 0;
}


posted @ 2016-06-18 10:07  Code-dream  阅读(279)  评论(0编辑  收藏  举报