最小生成数总结<2021.August.2.Monday><第五篇>

本文详细介绍了Prim算法和Kruskal算法两种求解最小生成树的方法。Prim算法通过贪心思想逐步构建最小生成树,而Kruskal算法则是一条条边地遍历,将不属于同一连通分量的顶点通过边连接起来。文章提供了具体实现代码。

引子:类似贪心和搜索

1.理解 :整个图所有的点连接,且连接的路径上的权值是最小的。

 算法分析

 

    1.prim算法

<1>理解:看做两个集合,一个集合没有被遍历到,另一个集合被遍历到了。运用贪心的思想将最小值逐个入队。

<2>实现:创建数组vis用来表示是否入队。dis数组用来表示某个点到最小生成树的距离。f[n][m]二维数组用来表示n到m的距离。刚开始可以选择任意一点作为遍历的起点。

 附上代码

tot=0;vis[s]=true//s已入队
for(int i=1;i<=n;i++)
  dis[i]=f[s][i]//到最小生成树的值
for(int i=1;i<=n;i++)
{
    min1=9999999;
    k=0;
    for(int j=1;j<=n;j++)//找到离生成树最小的值,且未被遍历过
    {
        if(!vis[j]&&dis[j]<min1)
        {
            min1=dis[j];
            k=j;//标记最小值
        }
    }
    tot+=dis[k]//dis[0]=0
    vis[k]=true;
    for(int j=1;j<=n;j++)
    {
        if(dis[j]>f[k][j])
           dis[i]=f[s][i]//从新确定到树的距离
    }
}

心得:对于一题有除边权值以外的信息,例如:《新的开始》一题还多了个在点上建发电场的费用,我们可以多设置一个点,遍历这个点到其他点的距离,在按照模板做即可。

  2.kruskal

1.理解:一条条边地遍历,如果那条边符合两端点不在一个集合就使用。

2.实现:运用并查集的知识,设一个fa[ ]数组,如果遍历到的边的数量达到k-1条(k为点的数量,联通所有的边最少需要k-1条边)。

代码

int find(int x)//找到x的父亲
{
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
bool cmp(const student a,const sttudent b)
{
    return a.w<a.w;//费用小的在前边
}
sort(a+1,a+1+n)
for(int i=1;i<=n;i++)
    fa[i]=i;//初始化每条边的父亲
for(int i=1;i<=m;i++)
{
    int r1=find(a[x].x),r2=find(a[x].y);//找到两端点各自的父亲
    if(r1!=r2)//父亲不相同
    {
        fa[r1]=r2;
        tot+=a[i].w;//边权值之和
        if(k==n-1)//达到了要求
            cout<<tot;    
}

 就这样。。。。

 

 

 

 

 

#include <stdio.h> #include <windows.h> #include "time_display.h" static const char *cpc_s_time_weekzh[] = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}; static const char *cpc_s_time_weeken[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; static const char *cpc_s_time_weekjp[] = {"日", "月", "火", "水", "木", "金", "土"}; static const char *cpc_s_time_monthen[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; void v_s_time_Display_allformats(void) { for (U1 i = 1; i <= 5; ++i) { v_s_time_Display_format(i); } } void v_s_time_Display_format(U1 u1_format_index) { SYSTEMTIME t; GetLocalTime(&t); U2 y = t.wYear; U1 m = (U1)t.wMonth, d = (U1)t.wDay; U1 h24 = (U1)t.wHour, min = (U1)t.wMinute, sec = (U1)t.wSecond; U1 w = (U1)t.wDayOfWeek; U1 h12 = h24 % 12 == 0 ? 12 : h24 % 12; const char *ampm = (h24 >= 12) ? "PM" : "AM"; switch (u1_format_index) { case 1: printf("格式1:%u年%u月%u日 %s %u点%u分%u秒",y, m, d, cpc_s_time_weekzh[w], h24, min, sec); break; case 2: printf("格式2:%u/%u/%u %s %02u:%02u:%02u", y, m, d, cpc_s_time_weekzh[w], h24, min, sec); break; case 3: printf("格式3:%u/%u/%u %s %u:%02u:%02u(%s)",y, m, d, cpc_s_time_weekzh[w], h12, min, sec, ampm); break; case 4: printf("格式4:%s, %s %u, %u %02u:%02u:%02u",cpc_s_time_weeken[w], cpc_s_time_monthen[m - 1], d, y, h24, min, sec); break; case 5: printf("格式5:%u年%u月%u日(%s) %u:%02u:%02u(%s)",y, m, d, cpc_s_time_weekjp[w], h12, min, sec, ampm); break; default: printf("[错误] 无效格式编号:%u", u1_format_index); break; } } void v_s_time_Write_allformats_to_file(void) { FILE *fp = fopen("time_log.txt", "a"); if (!fp) { printf("[错误] 无法打开 time_log.txt "); return; } SYSTEMTIME t; GetLocalTime(&t); U2 y = t.wYear; U1 m = (U1)t.wMonth, d = (U1)t.wDay; U1 h24 = (U1)t.wHour, min = (U1)t.wMinute, sec = (U1)t.wSecond; U1 w = (U1)t.wDayOfWeek; U1 h12 = h24 % 12 == 0 ? 12 : h24 % 12; const char *ampm = (h24 >= 12) ? "PM" : "AM"; fprintf(fp, "格式1:%u年%u月%u日 %s %u点%u分%u秒",y, m, d, cpc_s_time_weekzh[w], h24, min, sec); fprintf(fp, "格式2:%u/%u/%u %s %02u:%02u:%02u",y, m, d, cpc_s_time_weekzh[w], h24, min, sec); fprintf(fp, "格式3:%u/%u/%u %s %u:%02u:%02u(%s)",y, m, d, cpc_s_time_weekzh[w], h12, min, sec, ampm); fprintf(fp, "格式4:%s, %s %u, %u %02u:%02u:%02u",cpc_s_time_weeken[w], cpc_s_time_monthen[m - 1], d, y, h24, min, sec); fprintf(fp, "格式5:%u年%u月%u日(%s) %u:%02u:%02u(%s)",y, m, d, cpc_s_time_weekjp[w], h12, min, sec, ampm); fprintf(fp, "----------------------------------------"); fclose(fp); }帮我完善一下
08-05
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值