最小生成树

Kruskal模板

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#define maxn 2000000

using namespace std;
typedef long long LL;
bool flag=false;


struct point{
    int x;
    int y;
}p[200];
//点的集合,有些时候会直接给出点的编号,就不用建立结构体和数组了
//如果给的点是坐标,需给点进行编号
struct edge{
    int start;
    int end;
    double w;//注意权值的数据类型
}e[30000];
//一定要注意边的集合元素至少是n*(n+1)/2个,n为点的数目
//直接写成n*n+n个元素保险
int father[200];//注意点的个数
int find(int x)
{
    return father[x]==x?x:father[x]=find(father[x]);
}
//x为点的编号,返回的是它父亲节点的编号
bool cmp(const edge &a,const edge &b)
{
    if(a.w<b.w) return true;
    else return false;
}

double Kruskal(int n,int r)
//注意要修改返回值类型,返回权值之和,有时候也会判断能否形成MST,n为点的数目,r为边的数目
{
    double ans=0;//注意其数据类型,与权值的数据类型相同,权值之和的累加器
    for(int i=0;i<=n;i++)
    father[i]=i;
    //初始化并查集
    sort(e,e+r,cmp);//排序,按权值从小到大排
    int k=0;
    for(int i=0;i<r;i++)
    {
        int x=find(e[i].start);int y=find(e[i].end);
        if(x!=y) {k++;ans+=e[i].w;father[x]=y;}
    }
    if(k==n-1) return ans;//判断能否形成MST
    else return 0;
}
int n,x,y;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            p[i].x=x,p[i].y=y;
        }
        int r=0;
        for(int i=0;i<n;i++)
        {
            for(int j=i+1;j<n;j++)
            {
                e[r].start=i;
                e[r].end=j;
                int x2=p[i].x-p[j].x;
                int y2=p[i].y-p[j].y;
                double dis=sqrt(x2*x2+y2*y2);//有时候会限定权值范围,即舍去一些边要注意
                e[r].w=dis;
                r++;
                //依次记录每条边的起点、终点、权值并编号
            }
        }
        int flag=(int)Kruskal(n,r);
        if(flag) printf("%.1lf\n",Kruskal(n,r)*100);//如果成功找到
        else printf("………………");//否则……………………
    }
    return 0;
}

prime模板(用邻接矩阵):

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#define INF 0x3f3f3f3f

using namespace std;
typedef long long LL;

int map[200][200],lowcost[200];//map[][]代表的是邻接矩阵,注意点的个数,lowcost代表最小生成树里的点与不是最小生成树的点的边的权;
bool visit[200];//代表最小生成树这个集合即用过这个点就将其染黑;

int prime(int n)//注意返回值类型,返回的是权值,n代表点的数目
{
    int min,sumw=0;//注意类型,与权值的类型相同
    int k,c=0;
    memset(visit,false,sizeof(visit));
    visit[1]=true;
    for(int i=1;i<=n;i++)  //注意点的编号是从1开始
       lowcost[i]=map[1][i];
    for(int i=1;i<=n;i++)
    {
        min=INF;
        for(int j=1;j<=n;j++)
        {
            if(!visit[j]&&min>lowcost[j])
          {
              min=lowcost[j];
              k=j;
          }
        }
          if(min==INF) break;
          visit[k]=true;
          sumw+=min;c++;
          for(int j=1;j<=n;j++)
             if(!visit[j]&&lowcost[j]>map[k][j])
             lowcost[j]=map[k][j];
    }
    if(c==n-1) return sumw;//如果找到这个树,返回权值
    else return 0;//没有找到,返回0
}
struct point{
    int x;
    int y;
}p[200]//点的集合,给出点的坐标,利用结构体将其编号

/*如果给的是点的坐标,
  for(int i=1;i<=n;i++)
  scanf("%d%d",&p[i].x,&p[i].y);
  for(int i=1;i<=n;i++)
  for(int j=1;j<=n;i++)
  {
      int x2=p[i].x-p[j].x;
      int y2=p[i].y-p[j].y;
      double dis=sqrt(x2*x2-y2*y2);
      map[i][j]=dis;
  }
  利用这个创造邻接矩阵*/
  
  
int main()
{
    int n;
    while(~scanf("%d",&n)&n)
    {
        for(int i=0;i<=200;i++)
        for(int j=0;j<=200;j++)
        map[i][j]=INF;//注意一定要初始化邻接矩阵
        int n1=n-1;
        while(n1--)
        {
            char start;int t;
            cin>>start>>t;
            while(t--)
            {
                char end;int w;
                cin>>end>>w;
                map[start-'A'+1][end-'A'+1]=w;
                map[end-'A'+1][start-'A'+1]=w;
            }//创造出邻接矩阵
        }
        printf("%d\n",prime(n));
    }
    return 0;
}

prime(邻接表):用的是最常规的结构体内带有指针表示链表,可以用链表或数组表示,然后用优先队列,进行选最小的边,现在还不是太会,努力以后一定补充完整。

以下程序参考于https://blog.csdn.net/qq_35644234/article/details/59106779

#include <iostream>
#include <cstdio>
#include <cstring>
#define INF 0x3f3f3f3f

using namespace std;

struct edge{
    int toppoint;
    int weight;
    edge* next1;
};
struct top_pointlist{
    edge * edge1;
};
struct Graph_List{
    int toppoint_number;
    int edge_number;
    top_pointlist*list;
}g1;
void creatGraph(Graph_List&g)
{
    cin>>g.toppoint_number>>g.edge_number;
    g.list=new top_pointlist[g.toppoint_number];
    int i;
    for(int i=0;i<g.toppoint_number;i++)
    {
        g.list[i].edge1=NULL;
    }
    for(int i=0;i<g.edge_number;i++)
    {
        int start;
        int end;
        int weight;
        cin>>start>>end>>weight;
        edge*next=new edge;
        next->toppoint=end-1;
        next->weight=weight;
        next->next1=NULL;
        if(g.list[start-1].edge1==NULL) g.list[start-1].edge1=next;
        else
        {
            edge* temp;
            temp=g.list[start-1].edge1;
            while(temp->next1)
            {
                temp=temp->next1;
            }
            temp->next1=next;
        }
        edge*next2=new edge;
        next2->toppoint=start-1;
        next2->weight=weight;
        next2->next1=NULL;
        if(g.list[end-1].edge1==NULL) g.list[end-1].edge1=next2;
        else
        {
            edge* temp;
            temp=g.list[end-1].edge1;
            while(temp->next1)
            {
                temp=temp->next1;
            }
            temp->next1=next2;
        }
    }
}
void print(Graph_List g)//打印图
{
    for(int i=0;i<g.toppoint_number;i++)
    {
        edge*next;
        next=g.list[i].edge1;
        while(next)
        {
            cout << "("<< next->toppoint <<")="<<next->weight << " ";
            next = next->next1;
        }
        cout<<"<"<<endl;
    }
}
struct close_edge{
    int start;
    int end;
    int weight;
} c_edge[100];//边的个数
void prime(Graph_List g, int begin)
{
    int w=0;//权的累加器,注意类型
    for(int j=0;j<g.toppoint_number;j++)
    c_edge[j].weight=INF;
    edge*temp= g.list[begin-1].edge1;
    while(temp)
    {
        c_edge[temp->toppoint].end=temp->toppoint;
        c_edge[temp->toppoint].start=begin-1;
        c_edge[temp->toppoint].weight = temp->weight;
        temp = temp->next1;
    }
     c_edge[begin - 1].weight = -1;
     for (int j = 1; j < g.toppoint_number; j++) {
        int min = INF;
        int k;
        int index;
        /*寻找数组c_edge中权重最小的那个边*/
        for (k = 0; k < g.toppoint_number; k++) {
            if (c_edge[k].weight != -1) {
                if (c_edge[k].weight < min) {
                    min = c_edge[k].weight;
                    index = k;
                }
            }
        }
        if(min!=INF) w+=min;
        c_edge[index].weight = -1;
        /*更新我们的c_edge数组。*/
        edge * temp = g.list[c_edge[index].end].edge1;
        while (temp) {
            if (c_edge[temp->toppoint].weight > temp->weight) {
                c_edge[temp->toppoint].weight = temp->weight;
                c_edge[temp->toppoint].start = index;
                c_edge[temp->toppoint].end = temp->toppoint;
            }
            temp = temp->next1;
        }
    }
    printf("%d\n",w);
}

int main()
{
    creatGraph(g1);
    print(g1);
    prime(g1,1);
    cout << "Hello world!" << endl;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值