hdu1233 最小生成树Prim算法和Kruskal算法

Prim算法

时间复杂度:O(\(N^2\),N为结点数)

说明:先任意找一个点标记,然后每次找一条最短的两端分别为标记和未标记的边加进来,再把未标记的点标记上。即每次加入一条合法的最短的边,每次扩展一个点由未标记为已标记,直至扩展为N个点。

#include<stdio.h>
#include<string.h>
#define MAX 100000000
int map[101][101],visit[101];  /*map[x][y]记录x点到y点的距离,visit[],记录点是否标记。*/
long long prim(int n);
int main()
{
    int n;
    while(scanf("%d",&n)&&n)
    {
        int m = n*(n-1)/2;
        int i,j,a,b,c;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                if(i==j) map[i][j] = 0;
                else map[i][j]=map[j][i]=MAX;
            }
        }
        for(i=0;i<m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            map[a][b]=map[b][a]=c;   /*初始完map[][]*/
        }
        long long ans = prim(n);
        printf("%lld\n",ans);
    }
    return 0;
}
long long prim(int n)
{
    long long ans = 0;
    int minimal[510],i,j,min,k;
    memset(minimal,0,sizeof(minimal));
    memset(visit,0,sizeof(visit));
    visit[1] = 1;   /*从1开始,标记1*/
    for(i=1;i<=n;i++) minimal[i] = map[1][i];     /*得到从开始点到其它个点的距离。*/
    for(i=1;i<n;i++)
    {
        min = MAX;
        for(j=1;j<=n;j++)
        {
            if(minimal[j]<min&&visit[j]==0)
            {
                min = minimal[j];    /*得到其它未标记点到标记点的最短距离。*/
                k = j;     /*得到最短距离的未标记点*/
            }
        }
        ans += min;
        visit[k] = 1;     /*把未标记点标记*/
        for(j=1;j<=n;j++)
        {
            if(minimal[j]>map[k][j]&&visit[j]==0&&k!=j)
            {
                minimal[j] = map[k][j];    /*重新初始其它未标记点到标记点的距离,若其它未标记点到新标记点k的距离更短则替换。*/
            }
        }
    }
    return ans;
}

Kruskal算法

时间复杂度:O(\(M\log_2{M}\),M为边数)

说明:Kruskal是通过一个贪心的想法,每次取剩下的边权最小的边,如果加上这条边以后图中出现一个环,则破坏了生成树的性质,就不选这条边。依次进行直到整张图出现一颗生成树为止。

hdu的oj里的G++好像不支持二维数组排序,这个代码不能过

#include<stdio.h>
#define N 105
int set[N];
int comp(const void *a,const void *b);
long long as(int sz[][3],int n,int a);
int fine(int a);
int main()
{
    int n;
    while(scanf("%d",&n)&&n)
    {
        int m = n*(n-1)/2;
        int sz[m][3],i;
        for(i=0;i<m;i++)
        {
            scanf("%d%d%d",&sz[i][0],&sz[i][1],&sz[i][2]);
        }
        for(i=0;i<N;i++) set[i] = i;
        qsort(sz,m,sizeof(int)*3,comp);
        long long ans = as(sz,m,n);
        printf("%lld\n",ans);
    }
    return 0;
}
int comp(const void *a,const void *b)
{
    return ((int *)a)[2]-((int *)b)[2];
}
int fine(int a)
{
    return a==set[a] ? a : (set[a]=fine(set[a]));
}
long long as(int sz[][3],int n,int a)
{
    long long ans = 0;
    int i;
    for(i=0;i<n;i++)
    {
        if(fine(sz[i][0])!=fine(sz[i][1]))
        {
            set[fine(sz[i][1])] = fine(sz[i][0]);
            ans += sz[i][2];
            a--;
            if(a==1) break;
        }
        else continue;
    }
    return ans;
}

重新把二维数组排序写成函数后就可以过了。

#include<stdio.h>
#define N 105
int set[N];
void qsort(int sz[][3],int a);  /*二维数组排序的函数*/
long long as(int sz[][3],int n,int a);
int fine(int a);
int main()
{
    int n;
    while(scanf("%d",&n)&&n)
    {
        int m = n*(n-1)/2;
        int sz[m][3],i;
        for(i=0;i<m;i++)
        {
            scanf("%d%d%d",&sz[i][0],&sz[i][1],&sz[i][2]);
        }
        for(i=0;i<N;i++) set[i] = i;
        qsort(sz,m);    /*按边排序*/
        long long ans = as(sz,m,n);
        printf("%lld\n",ans);
    }
    return 0;
}
void qsort(int sz[][3],int a)
{
    int i,j,x,exchange;
    for(i=0;i<a-1;i++)
    {
        for(j=i+1;j<a;j++)
        {
            if(sz[i][2]>sz[j][2])
            {
                for(x=0;x<3;x++)
                {
                    exchange = sz[i][x];
                    sz[i][x] = sz[j][x];
                    sz[j][x] = exchange;
                }
            }
        }
    }
}
int fine(int a)
{
    return a==set[a] ? a : (set[a]=fine(set[a]));
}
long long as(int sz[][3],int n,int a)
{
    long long ans = 0;
    int i,j;
    for(i=0;i<n;i++)
    {
        if(fine(sz[i][0])!=fine(sz[i][1]))   /*连接该边不构成环*/
        {
            set[fine(sz[i][1])] = fine(sz[i][0]);
            ans += sz[i][2];
            j++;
            if(j==a-1) break;   /*边数==点数-1即生成树完成。*/
        }
    }
    return ans;
}
上一篇:最小生成树详解


下一篇:Springboot集成Websocket不能使用@Autowired注入service