woj 1038 最小生成树

题意就是给你一个长为L的绳子,然后给出n个点,问能不能把所有点都连接在一起

prime算法:

首先两个集合,集合1只含一个顶点A,集合2含有剩下的n-1个顶点,重复下面的操作n-1次

找出集合2中顶点与顶点A连接的最短边,将这个顶点B从集合2移入集合1中,下次使用B继续找顶点

代码实现如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define MAXV 100//后面都会用到
#define INF 32768//INF表示正无穷
typedef struct
{
    int x,y;
}Point;
struct MGraph
{
    double edges[MAXV][MAXV];//邻接矩阵的边数组
    int n;//顶点数,弧度;
};
MGraph g;
double sum;
double distan(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
void Prime(MGraph g,int v)
{
    double lowcost[MAXV];
    int closest[MAXV];
    int i,j,k;
    double min;
    for(i=0;i<g.n;i++)//给lowcost[]和closest赋初值,
    {
        lowcost[i]=g.edges[v][i];
        closest[i]=v;
    }
    for(i=1;i<g.n;i++)//找出n-1个顶点
    {
        min=INF;
        for(j=0;j<g.n;j++)//在V-U中找出离U最近的顶点k
            if(lowcost[j]!=0 && lowcost[j]<min)
            {
                min=lowcost[j]; k=j;//k记录最近顶点的编号
            }
        sum +=min;
        //cout<<k<<" "<<sum<<endl;
        lowcost[k]=0;//标记k已经加入U
        for(j=0;j<g.n;j++)//修改数组lowcost和closest
            if(g.edges[k][j]!=0 && g.edges[k][j]<lowcost[j])
            {
                lowcost[j]=g.edges[k][j];  closest[j]=k;
            }
    }
}
int main()
{
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int n,l,i,j;
    Point a[100];
    while(cin>>n && n)
    {
        cin>>l;
        g.n=n;
        for(i=0;i<n;i++) cin>>a[i].x>>a[i].y;
        for(i=0;i<n;i++)
        for(j=0;j<n;j++)
        {
            if(i==j) g.edges[i][j]=0.0;
            else g.edges[i][j]=distan(a[i],a[j]);
        }
        sum=0.0;
        Prime(g,0);
        if(sum<=l) cout<<"Success!"<<endl;
        else cout<<"Poor magicpig!"<<endl;
    }
    return 0;
}

kruskal算法:

因为之前看kruskal算法有点小长,没有prime算法简洁,所以我就给过了,今天好好看了一下,写的第一个kruskal,很多地方没有写简洁,大家可以去之后更新的"kruskal算法 模板"

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define MAXV 100//后面都会用到
#define MAXSIZE (100*100)
#define INF 100000//INF表示正无穷
typedef struct
{
    int x,y;
}Point;
struct MGraph
{
    double edges[MAXV][MAXV];//邻接矩阵的边数组
    int n;//顶点数,弧度;
};
MGraph g;
double sum;
double distan(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
//并查集
int Father[MAXV]; // Father[i] 表示 i 的父节点
int Rank[MAXV];// rank[ x ] 表示 x 的秩
void MakeSet(int x)
{
    Father[ x ] = x;
    Rank[ x ] = 1;//不需要使用rank时不需要声明这个
}
int FindSet(int x)
{
    while (x != Father[x]) x = Father[x];
    return x;
}
void Union(int x, int y)
{
    x = FindSet( x ); //查找 x 的祖先
    y = FindSet( y ); //查找 y 的祖先
    if(x == y) return;
    if(Rank[x] > Rank[y])
    {
        Father[y] = x; //合并后祖先为 x
        Rank[x] += Rank[y]; //合并秩
    }
    else
    {
        Father[x] = y; //合并后祖先为 y
        Rank[y] += Rank[x]; //合并秩
    }
}
struct Edge//边
{
    int p1,p2;
    double val;
};
bool cmp(Edge a,Edge b)
{
    return a.val < b.val;//按照边从小到大排序
}
void Kruskal(MGraph g)
{
    Edge e[MAXSIZE];//边数组
    int i,j,k=0;
    //对边进行排序
    for(i=0;i<g.n;i++)
    for(j=0;j<g.n;j++)
       if(g.edges[i][j]!=0 && g.edges[i][j]!=INF)
       {
           e[k].p1=i; e[k].p2=j; e[k].val=g.edges[i][j];
           k++;
       }
    sort(e,e+k,cmp);
    //初始化并查集
    for(i=0;i<g.n;i++) MakeSet(i);
    //处理
    k=1; j=1;
    while(k<g.n)
    {
        if(FindSet(e[j].p1)!=FindSet(e[j].p2))
        {
            k++; sum +=e[j].val; Union(e[j].p1,e[j].p2);
        }
        j++;
    }
}
int main()
{
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int n,l,i,j;
    Point a[100];
    while(cin>>n && n)
    {
        cin>>l;
        g.n=n;
        for(i=0;i<n;i++) cin>>a[i].x>>a[i].y;
        for(i=0;i<n;i++)
        for(j=0;j<n;j++)
        {
            if(i==j) g.edges[i][j]=0.0;
            else g.edges[i][j]=distan(a[i],a[j]);
        }
        sum=0.0;
        Kruskal(g);
        if(sum<=l) cout<<"Success!"<<endl;
        else cout<<"Poor magicpig!"<<endl;
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

daydaytech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值