prim算法,克鲁斯卡尔算法---最小生成树

最小生成树的一个作用,就是求最小花费。要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此另一个目标是要使铺设光缆的总费用最低。这就需要找到带权的最小生成树

主要思路:贪心,假设一共有五个点,按道理来讲,应该是先找到图中最小权值的两个点没然后对剩余的点进行遍历。但是也可以任意指定一个点。可以任意指定的原因就是,如果给定的信息可以构成最小生成树的话,那么最小生成树中一定有所有的点,那么这个点也一定在树上,所以可以任意指定一个点进行循环。指定第一个点后,然后寻找其他还没有访问的点到该点的最小距离,找到之后,将该点放入已经访问过的集合中,然后再找剩下的未访问的点到已经访问的这一坨中的点的最小距离,然后不停的循环这个过程,知道所有的点都访问为止。(如果是最大生成树的话,直接改克鲁斯卡尔中的sort就可以了,最小生成树是升序,最大生成树就是降序)

例题:http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Index/problemdetail/pid/2144.html

代码:(Prim)

#include<iostream>
#include<cstring>
#include<string>
#include<iomanip>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
# define maxn  1005
# define inf 0x3f3f3f3f
int a[maxn][maxn];
int dis[maxn];
int n,m;
int vis[maxn];
int flag;
int prime()
{
    for(int i=1; i<=n; i++)
        dis[i]=a[i][1];//首先把除了1之外的点的距离到1的距离存好
memset(vis,0,sizeof(vis));//标记数组
vis[1]=1;
int temp,k;
int sum=0;//计算权值和
for(int i=1; i<n; i++)
{
    temp=inf;
    for(int j=1; j<=n; j++)
    {
        if(vis[j]==0&&dis[j]<temp)//寻找剩余的点到已经访问过的集合中的距离的最小值
        {
            temp=dis[j];
            k=j;
        }
    }
    if(temp==inf)//如果这个点连不到图上,说明根本无法构成图,直接退出即可
    {
        flag=1;
        break;
    }
    sum+=temp;
    vis[k]=1;//将下一个点标记
    for(int j=1; j<=n; j++)
    {
        if(vis[j]==0&&dis[j]>a[k][j])//dis数组存的不只是剩余的点到k点的最小距离,还应该是剩余的点到已经访问过的点的u最小距离。
        {
            dis[j]=a[k][j];
        }
    }
}
return sum;
}
int main()
{
    while(cin>>n>>m)
    {
        memset(a,inf,sizeof(a));//首先对存图的数组进行初始化
        for(int i=1; i<=n; i++)
        {
            a[i][i]=0;
        }//自己到自己的距离是0
        flag=0;
        for(int i=1; i<=m; i++)
        {
            int u,v,w;
            cin>>u>>v>>w;
            if(a[u][v]>w)//防止有重边
            {
                a[v][u]=a[u][v]=w;
            }
        }
        int t=prime();
        if(m<n-1||flag==1)cout<<0<<endl;//如果,有的点连不到图上,或者给定的信息根本无法构成图,则输出0
        else
        {
            cout<<t<<endl;
        }
    }
    return 0;
}

克鲁斯卡尔算法:

#include<iostream>
#include<iomanip>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
# define maxn 10000+10
int n,m;
struct node
{
    int x,y,cost;
} edge[maxn];
int father[maxn];
int Find(int t)
{
    return father[t]==t? t: father[t]=Find(father[t]);
}
bool cmp(node t1,node t2){
return t1.cost<t2.cost;
}
int kruskal()
{
    for(int i=1; i<=n; i++)
    {
        father[i]=i;
    }
    int sum=0;
    sort(edge+1,edge+m+1,cmp);
    for(int i=1; i<=m; i++)
    {
        int t1=Find(edge[i].x);
        int t2=Find(edge[i].y);
        if(t1!=t2)
        {
            sum+=edge[i].cost;
            father[t1]=t2;
        }
    }
    return sum;
}
int main()
{
    while(cin>>n>>m)
    {
        for(int i=1; i<=m; i++)
        {
            cin>>edge[i].x>>edge[i].y>>edge[i].cost;
        }
        int t=kruskal();
        cout<<t<<endl;
    }
    return 0;
}

 

posted @ 2018-07-31 17:25  Let_Life_Stop  阅读(341)  评论(0编辑  收藏  举报