最小生成树 (hdu)1102 1162 1233 1301 1863 7875 7873

大家都知道最小生成树有两种算法:prim(普利姆)———从点考虑,kruskal(克鲁斯卡)————从边考虑

初学最小生成树时,看的这篇博文,感觉棒棒哒点击打开链接

点击打开链接

 

hdu 1233 最小生成树
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#define N 100100
using namespace std;
struct node{
    int a,b,c;
}mapp[N];
int fa[N];
int com(node t1,node t2){
    return t1.c<t2.c;///按权重小的将边排序
}
///并查集查找每个点的父亲节点来判断两点是否都已经加入新图中以及判断图是否连通
int findfa(int x){
    if(x!=fa[x])
        fa[x]=findfa(fa[x]);
    return fa[x];
}
int main(){
    int n,m,i,fx,fy,res;
    while(scanf("%d",&n)!=EOF&&n){
       m=n*(n-1)/2;
       res=0;
       for(i=1;i<=n;i++) fa[i]=i;
       for(i=1;i<=m;i++)
            scanf("%d %d %d",&mapp[i].a,&mapp[i].b,&mapp[i].c);
       sort(mapp+1,mapp+m+1,com);
       for(i=1;i<=m;i++){
            fx=findfa(mapp[i].a);   fy=findfa(mapp[i].b);
             if(fx!=fy){///若附近节点不同,就把它两之间的边加入新图中
                fa[fx]=fy;///并且使其中任意一方的父亲节点更新成另一方的父亲节点
                res+=mapp[i].c;
                --n;
            }
       }
       printf("%d\n",res);
    }
    return 0;
}

hdu 1162

 

点击打开链接

 

<span style="font-size:14px;">普莱姆算法  prim</span>
#include<stdio.h>
#include <string.h>
#include<stdlib.h>
#include <math.h>
#include <algorithm>
using namespace std;
int mark[11000],n;
double mapp[11000][11000],dist[11000],left[11000],right[11000];
///函数也要变类型
double prim(){
    int i,j,k;
    double sum=0.0,min;
    for(i=0;i<n;i++)
    dist[i]=mapp[0][i];
    dist[i]=0,mark[0]=1;
    for(i=1;i<n;i++){
        min=1542487693.00,k=-1;//这里的min也要变成double类型
        for(j=0;j<n;j++)
        if(dist[j]<min&&mark[j]==0){
            min=dist[j];
            k=j;
        }
        mark[k]=1;
        if(k==-1)    break;
        else{
        sum+=dist[k];
        for(j=0;j<n;j++)
        if(mark[j]==0&&mapp[k][j]<dist[j])
        dist[j]=mapp[k][j];
        }
    }
    return sum;
}
int main()
{
    int i,j,k;
    double ans=0.0;
    while(scanf("%d",&n)!=EOF){
        memset(mark,0,sizeof(mark));
        for(i=0;i<n;i++)
        scanf("%lf %lf",&left[i],&right[i]);//注意是double类型的
        for(i=0;i<n;i++)
            for(j=0;j<n;j++)
                if(i!=j){
                    mapp[i][j]=sqrt((left[i]-left[j])*(left[i]-left[j])+(right[i]-right[j])*(right[i]-right[j]));
                    mapp[j][i]=mapp[i][j];
                }
        ans=prim();
        printf("%.2f\n",ans);  
    }
    return 0;
}           
克鲁斯卡算法 kruskal
#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int m,per[500];
struct node {
    int x,y;
    double dis;//注意类型
}s[10000000];
double cmp(node x,node y)
{
    return x.dis<y.dis;
}
int find(int x)
{
    /*非递归法查找父亲结点
    int i=x,t=x,j;
    while(t!=per[t])
    t=per[t];
    while(i!=t)
    {
        j=per[i];
        per[i]=t;
        i=j;
    }
    return t;
    */
    if(x!=per[x])
    per[x]=find(per[x]);
    return per[x];
}
int main()
{
    int i,j,t,fx,fy;;
    double a[500],b[500],sum;
    while(scanf("%d",&m)!=EOF){
    for(i=0;i<m;i++)    per[i]=i;
    for(i=0;i<m;i++)
        scanf("%lf %lf",&a[i],&b[i]); 
    t=0;sum=0.0;
    for(i=0;i<m;i++)
    {
        for(j=0;j<i;j++)
        {
            s[t].x=i;
            s[t].y=j;
            double q=(sqrt((a[i]-a[j])*(a[i]-a[j])+(b[i]-b[j])*(b[i]-b[j])*1.0));
            ///if(q<=1000&&q>=10)
            s[t++].dis=q;
        }
    }
    sort(s,s+t,cmp);
    for(i=0;i<t;i++)
    {
        fx=find(s[i].x),fy=find(s[i].y);
        if(fx!=fy){
        per[fx]=fy;
        sum+=s[i].dis;
        }
    }
    printf("%.2f\n",sum);
    }
    return 0;
}

hdu 1102

 

点击打开链接

 

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#define Y 0x3f3f3f3f
#define N 11100000
using namespace std;
int n,mapp[350][350],dist[350],mark[350];
int prim(){
    memset(mark,0,sizeof(mark));
    int i,j,minn,k,sum=0;
    for(i=1;i<=n;i++)
    dist[i]=mapp[1][i];
    dist[1]=0,mark[1]=1;
    for(i=1;i<n;i++){
        minn=Y,k=-1;
        for(j=1;j<=n;j++)
        if(mark[j]==0&&dist[j]<minn){
            minn=dist[j];
            k=j;
        }
        mark[k]=1;
        if(k==-1)    break;///若图不连通
        else{
            sum+=dist[k];
            for(j=1;j<=n;j++)
            if(mark[j]==0&&mapp[k][j]<dist[j])
            dist[j]=mapp[k][j];
        }
    }
    return sum;
}
int main() {
    int m,a,b,y,i,j;
    while(scanf("%d",&n)!=EOF){
    for(i=1;i<=n;i++)
    for(j=1;j<=n;j++)
    scanf("%d",&mapp[i][j]);
    scanf("%d",&m);///强已经建好的路权重归零
    for(i=1;i<=m;i++){
    scanf("%d %d",&a,&b);
    mapp[a][b]=mapp[b][a]=0;
    }
    y=prim();
    printf("%d\n",y);
    }
    return 

hdu 1874

 

点击打开链接

 

普莱姆算法
#include <iostream>
#include <queue>
#include <string.h>
#define Y 111100
#define N 1100
using namespace std;
int mapp[N][N],mark[N],dist[N],n,m,s,t;
void dijsta(int v0){
    int i,j;
    for(i=0;i<n;i++)
        dist[i]=mapp[v0][i];
    mark[v0]=1;  dist[v0]=0;
    for(i=1;i<n;i++){
        int minn=Y,k=-1;
        for(j=0;j<n;j++)
            if(minn>dist[j]&&mark[j]==0)
            {   minn=dist[j];
                k=j;
            }
        mark[k]=1;
        if(k!=-1){
            for(j=0;j<n;j++)
                if(mapp[k][j]<Y&&mark[j]==0){
                    if(dist[k]+mapp[k][j]<dist[j])
                        dist[j]=dist[k]+mapp[k][j];
                }
        }
    }
}
int main()
{
    int a,b,c,i,j,y=0;
    while(cin>>n>>m){
        memset(mark,0,sizeof(mark));
        memset(dist,0,sizeof(dist));
        for(i=0;i<n;i++){
            for(j=0;j<n;j++){
                mapp[i][j]=Y;
            }
        }
        for(i=0;i<m;i++){
            cin>>a>>b>>c;
            if(mapp[a][b]>c)
            mapp[a][b]=mapp[b][a]=c;
        }
        cin>>s>>t;
        dijsta(s);
        y=dist[t];
        if(y==Y)
            cout<<"-1"<<endl;
        else
            cout<<y<<endl;
    }

    return 0;
}

 

 

 

 

 

hdu 1875

点击打开链接

 

普莱姆算法 prim
#include<stdio.h>
#include <string.h>
#include<stdlib.h>
#include <math.h>
#include <algorithm>
#define Y 111110000
using namespace std;
int mark[11000],n,left[11000],right[11000];
double mapp[11000][11000],dist[11000];
///注意类型
double prim(){
    int i,j,k;
    double sum=0.0,min;
    for(i=0;i<n;i++)
    dist[i]=mapp[0][i];
    dist[0]=0,mark[0]=1;
    for(i=1;i<n;i++){
        min=1542487693.00,k=-1;
        for(j=0;j<n;j++)
        if(dist[j]<min&&mark[j]==0){
            min=dist[j];
            k=j;
        }
        mark[k]=1;
        if(k==-1) break;    ///若没找到满足条件的下标
        else{
        sum+=dist[k];
        for(j=0;j<n;j++)
        if(mark[j]==0&&mapp[k][j]<dist[j])
        dist[j]=mapp[k][j];
        }
    }
    return sum;
}
int main()
{
    int T,i,j,k;
    double ans=0.0,d;
    scanf("%d",&T);
    while(T--){
    scanf("%d",&n);
        memset(mark,0,sizeof(mark));
        for(i=0;i<n;i++)
        scanf("%d %d",&left[i],&right[i]);
        for(i=0;i<n;i++)
            for(j=0;j<n;j++)
                if(i!=j){
                    d=sqrt((left[i]-left[j])*(left[i]-left[j])+(right[i]-right[j])*(right[i]-right[j]));
                    if(d>=10&&d<=1000)
                    mapp[j][i]=mapp[i][j]=d;
                    else
                    mapp[j][i]=mapp[i][j]=Y;
                }
        ans=prim();
        if(ans<Y)
        printf("%.1lf\n",ans*100.0);  
        else
        printf("oh!\n");
    }
    return 0;
}             
克鲁斯卡算法 kruskal
#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int m,per[500],cot;
struct node {
    int x,y;
    double dis;
}s[10000000];
double cmp(node x,node y)
{
    return x.dis<y.dis;
}
int find(int x)
{
    /*
    int i=x,t=x,j;
    while(t!=per[t])
    t=per[t];
    while(i!=t)
    {
        j=per[i];
        per[i]=t;
        i=j;
    }
    return t;
    */
    if(x!=per[x])
    per[x]=find(per[x]);
    return per[x];
}
int main()
{
    int N,n,a[300],b[300],i,j;
    scanf("%d",&N);
    while(N--)
    {
        cot=0;
        scanf("%d",&m);
        for(i=0;i<m;i++)
        per[i]=i;
        for(i=0;i<m;i++)
            scanf("%d%d",&a[i],&b[i]);
            int t=0;
        for(i=0;i<m;i++)
        {
            for(j=0;j<i;j++)
            {
                s[t].x=i;
                s[t].y=j;
                double q=(sqrt((a[i]-a[j])*(a[i]-a[j])+(b[i]-b[j])*(b[i]-b[j])*1.0));
                if(q<=1000&&q>=10)
                s[t++].dis=q;
            }
        }
        sort(s,s+t,cmp);
        double sum=0;
        int fx,fy;
        for(i=0;i<t;i++)
        {
            fx=find(s[i].x),fy=find(s[i].y);
            if(fx!=fy){
            cot++;
            per[fx]=fy;
            sum+=s[i].dis;
            }
        }
        if(cot!=m-1)
        printf("oh!\n");
        else
        printf("%.1lf\n",sum*100);
    }
    return 0;
}

hdu 1879

 

点击打开链接

 

普莱姆算法
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <string.h>
#define N 200
#define Y 900
using namespace std;
int n,m,dist[N],mapp[N][N],mark[N];
int Prime()
{
    int sum=0,i,j;
    for(i=1;i<=n;i++)
        dist[i]=mapp[1][i];
    mark[1]=1;dist[1]=0;
    for(i=1;i<n;i++){
        int minn=Y,k=-1;
        for(j=1;j<=n;j++)
            if(minn>dist[j]&&mark[j]==0)
            {   minn=dist[j];
                k=j;
            }
        mark[k]=1;
        if(k!=-1){
            sum+=dist[k];
            for(j=1;j<=n;j++)
                if(dist[j]>mapp[k][j]&&mark[j]==0)
                    dist[j]=mapp[k][j];
        }
    }
    return sum;
}

int main()
{
    int i,j;
    int a,b,c,d;
    while(scanf("%d",&n)!=EOF&&n){
    m=n*(n-1)/2;memset(
    mark,0,sizeof(mark));
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        mapp[i][j]=Y;
    for(i=1;i<=m;i++){
        scanf("%d %d %d %d",&a,&b,&c,&d);
        if(d==0)
            mapp[a][b]=mapp[b][a]=c;
        else
            mapp[a][b]=mapp[b][a]=0;
    }
    printf("%d\n",Prime());
    }
    return 0;
}
克鲁斯卡算法
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#define N 200
using namespace std;
struct node{
    int a,b,c;
}mapp[N*N];
int fa[N];
int com(struct node t1,struct node t2){
    return t1.c<t2.c;
}
int findfa(int x){
    if(x!=fa[x])
        fa[x]=findfa(fa[x]);
    return fa[x];
}
int main()
{
    int n,i,fx,fy,res,t;
    while(scanf("%d",&n)&&n){
    res=0;
    for(i=1;i<=n;i++)   fa[i]=i;
    for(i=1;i<=n*(n-1)/2;i++){
    scanf("%d %d %d %d",&mapp[i].a,&mapp[i].b,&mapp[i].c,&t);
    if(t==1)
    mapp[i].c=0;
    }
    sort(mapp+1,mapp+n*(n-1)/2+1,com);
    for(i=1;i<=n*(n-1)/2;i++){
        fx=findfa(mapp[i].a);   fy=findfa(mapp[i].b);
        if(fx!=fy){
            fa[fx]=fy;
            res+=mapp[i].c;
        }
    }
    printf("%d\n",res);
    }
    return 0;
}

hdu 1301   前面感觉都是模板,这次来点不同的最小生成树,不同就在于n表示点的个数,而每个点的标号不在是数字而是大写字母,每行首个大写字母的后面的数字表示有几个点与行首大写字母相连,后面的数字表示两点之间的权重。求是图连通的最小生成树

 

点击打开链接

克鲁斯卡算法
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#define N 100100
using namespace std;
struct node{
    int a,b,c;
}mapp[N];
int fa[N];
int com(node t1,node t2){
    return t1.c<t2.c;
}
int findfa(int x){
    if(x!=fa[x])
        fa[x]=findfa(fa[x]);
    return fa[x];
}
int main(){
    int n,m,i,j,p,q,fx,fy,res,l;
    char c1,c2;
    while(scanf("%d%*c",&n)!=EOF&&n){
       m=n-1;
       res=0;
       l=0;
       for(i=1;i<=n;i++) fa[i]=i;
       for(i=1;i<=m;i++){
            scanf("%c %d%*c",&c1,&p);
            for(j=1;j<=p;j++){
                scanf("%c %d%*c",&c2,&q);///%*c相当于getchar()
                l++;
                mapp[l].a=c1-'A'+1; mapp[l].b=c2-'A'+1; mapp[l].c=q;///把每个字母编号转换成数字编号
            }

       }
       sort(mapp+1,mapp+l+1,com);
       for(i=1;i<=l;i++){
            fx=findfa(mapp[i].a);   fy=findfa(mapp[i].b);
            if(fx!=fy){
                fa[fx]=fy;
                res+=mapp[i].c;
                --n;
            }
       }
       printf("%d\n",res);
    }
    return 0;
}

hdu 1863

 

点击打开链接

普莱姆算法 
<pre name="code" class="html">#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#define N 200
#define Y 33333110
using namespace std;
int mapp[N][N],mark[N],dist[N],n,m,sum;
int prim(int v0){
    memset(mark,0,sizeof(mark));
    int i,j,minn,k,sum=0;
    for(i=1;i<=n;i++)
        dist[i]=mapp[v0][i];
    mark[v0]=1;  dist[v0]=0;
    for(i=1;i<n;i++){
        minn=Y;k=-1;
        for(j=1;j<=n;j++)
            if(mark[j]==0&&minn>dist[j]){
                minn=dist[j];
                k=j;
            }
        mark[k]=1;
        if(k==-1){
            return Y;
        }
        if(k!=-1){
            sum+=dist[k];
            for(j=1;j<=n;j++)
                if(mark[j]==0&&mapp[k][j]<dist[j])
                dist[j]=mapp[k][j];
            }
        }
    return sum;
}
int main()
{
    int i,j,a,b,c,y;
    while(cin>>m&&m){
        cin>>n;
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        mapp[i][j]=Y;
    for(i=1;i<=m;i++){
        cin>>a>>b>>c;
        if(mapp[a][b]>c)
        mapp[a][b]=mapp[b][a]=c;
    }
    y=prim(1);
    if(y==Y)
        cout<<"?"<<endl;
    else
        cout<<y<<endl;
    }
    return 0;
}

克鲁斯卡算法

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#define N 200
#define Y 33333110
using namespace std;
struct node{
    int a,b,c;
}mapp[N*6];
int fa[N*6];
int com(node t1,node t2){
    return t1.c<t2.c;
}
int findfa(int x){
    if(x!=fa[x])
        fa[x]=findfa(fa[x]);
    return fa[x];
}
int main()
{
    int n,m,i,fx,fy,res;
    while(cin>>m&&m){
        cin>>n;
    res=0;
    for(i=1;i<=n;i++)   fa[i]=i;
    for(i=1;i<=m;i++)
        cin>>mapp[i].a>>mapp[i].b>>mapp[i].c;
    sort(mapp+1,mapp+m+1,com);
    for(i=1;i<=m;i++){
        fx=findfa(mapp[i].a);   fy=findfa(mapp[i].b);
        if(fx!=fy){
            fa[fx]=fy;
            res+=mapp[i].c;
            --n;
        }
    }
    if(n>1)
        cout<<"?"<<endl;
    else
       cout<<res<<endl;
    }
    return 0;
}

我记得还有一道题,可是翻不到了,以后再来不吧
 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值