对最小生成树的认识及模板题

简介: 一周前对 树 这个词从新认识了一下,之前一直有听说过,但是很显然,仅仅是听说。。
  1. 树到底是个啥

通俗来讲,就是所有顶点都由一些边从而连在了一起,但是不包含回路的图

76998ae1c85a406e9e91dd30e175df2f.png
8ab6eaa5556047d0aeced985fa9c168f.png

  1. 最小生成树又是什么

我们知道上述树的生成是由很多点和边组成的,所以有可能因为边的不同会出现不同的树,现在如果每条边都有不同的权值,那么最小生成树就是所有树中所有的权值和最小的那个树

  1. 最小生成树的两种算法

3.1 prim算法
prim算法是通过对点的处理,通过找到一个点,然后再找到另一个点,找另一个点的标准就是这两个点之间边的权值应该最小。

板子

void prim()
{

for(int i=1; i<=n; i++) p[i]=e[1][i],book[i]=0;//先把p数组存入从一点到任一点的距离
book[1]=0;
int u=1;
int num=0;//记录用到了几个点 
int sum=0;//记录答案 
num++;//第一个点 
while(num<n)//当每个点都被连在一起的时候跳出循环
{
    int min1=inf; 
    for(int i=1; i<=n; i++)
    {
        if(!book[i]&&f[i]<min1)    //遍历找到最小的点 
        {
            min1=f[i];
            u=i;
        }
    }
    sum=sum+f[i];//记录答案 
    num++;//记录点 
    book[u]=1;//标记已经走过 
    for(int i=1; i<=n; i++)//从上次找到的点相邻的最小边 
    {
        if(!book[i]&&f[i]<e[u][i])
            f[i]=e[u][i]; 
    }
}
cout<<sum<<endl;

}

3.2 kruskal算法
kruskal和prim可以说恰恰是从另一个角度来考虑这个问题的,首先把所有边摘出来,从小到大排列,每次找边,总是找较小的边,不过如果两个点之间,已经存在直接或者间接相连的边,就不再需要更新这两个点之间的边了,为了实现这个操作就需要用到并查集。这里上代码比较清晰一点

//并查集板子
for(int i=1; i<=n; i++) d[i]=i;//这里是把d数组初始化成1234上升的对应序列
int findx(int x)
{

if(d[x]==x)//如果还是对应相等那么就返回原值
    return x;
else//否则就返回这个点的上级
    return d[x]=findx(d[x]);//注意这里如果直接返回findx(d[x])而不是返回d[x]=findx(d[x])有时候会报超时(不知道为啥子。。)

}
void merge(int x,int y)//查看任意两个点上级是否相等
{

int dx=findx(x);//首先找到这两点的上级
int dy=findx(y);
if(dx!=dy)//判断不相等就让左点变成右点的下级(这里也可以翻着无所谓了)
    d[dx]=dy;

}

然而完成了这个操作之后还有一步操作紧接着让我们实现,那就是对所有的边进行排序,这里常用的有两种办法

利用结构体排序
struct no
{

int x;//一个点 
int y;//另一个点 
int v;//两点之间的权值 

}e;
bool cmp(no a,no b)
{

return a.v < b.v;//从小到大排序    

}
sort(e,e+l,cmp);
void kruskal()
{

int sum=0;//记录走过的权值
int num=0;//记录用到了的点的个数
num++;//第一个点
while(num<n)//(n为点的总个数)
{
    
}

}

利用c++里面的优先队列排序
struct no
{

int x;//一个点 
int y;//另一个点 
int v;//两点之间的权值 

}e;
bool operator <(no a,no b)
{

return a.x > b.x;

}
priority_queuequ;
//利用优先队列,将数据存储在队列里面这样每次就会找到最小的边

  1. 一些模板题

第一题:
poj-1751(highways)

//这个题也是一个标准的kruskal算法

include

include

include

include

using namespace std;

const int inf=1e9;
const int N=10010;

int d[N],xx[N],yy[N];

struct no
{

int x;
int y;
double d;

}mp;
bool operator < (no a,no b)
{

return a.d > b.d;

}

int findx(int x)
{

if(d[x]==x)
    return x;
else
{
    d[x]=findx(d[x]);
    return d[x];
}

// else return findx(d[x]);
}

int merge(int x,int y)
{

int xx=findx(x);
int yy=findx(y);
if(xx!=yy)
{
    d[xx]=yy;
    return 1;
}
return 0;

}

double dmath(int x1,int y1,int x2,int y2)
{

return sqrt(1.0*(x1-x2)*(x1-x2)+1.0*(y1-y2)*(y1-y2));

}

int main()
{

int n;
scanf("%d",&n);
    priority_queue<no>qu;
    for(int i=1; i<=n; i++)
        scanf("%d%d",&xx[i],&yy[i]);
    for(int i=1; i<n; i++)
        for(int j=i+1; j<=n; j++)
        {
            mp.x=i;
            mp.y=j;
            mp.d=dmath(xx[i],yy[i],xx[j],yy[j]);

// printf("%.2lf \n",mp.d);

            qu.push(mp);
        }
    for(int i=1; i<=n; i++) d[i]=i;
    int m;
    scanf("%d",&m);
    while(m--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        merge(a,b);
    }
    int cut=0;
    while(!qu.empty())
    {
        mp=qu.top();
        qu.pop();
        if(merge(mp.x,mp.y))
        {    
            cut++;
            printf("%d %d\n",mp.x,mp.y);
        }
        if(cut==n-1) break;
    }
return 0; 

}

第二题:
poj–2349–Arctic Network
这个题就是让你从选中边里面找到一个最长边

include

include

include

include

include

using namespace std;

typedef double dou;
const int N=500+5;

dou d[N];
int xx[N],yy[N];
struct no
{

int x;
int y;
dou d;

}mp;
bool operator < (no a,no b)
{

return a.d > b.d;

}
dou dmath(dou x1,dou y1,dou x2,dou y2)
{

return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

}
int findx(int x)
{

if(d[x]==x)
    return x;
else return findx(d[x]);

}
int merge(int x,int y)
{

int t=findx(x);
int l=findx(y);
if(t!=l)
{
    d[l]=t;
    return 1;
}
return 0;

}
int n,s,p;
int main()
{

cin>>n;
while(n--)
{
    memset(xx,0,sizeof(xx));
    memset(yy,0,sizeof(yy));
    priority_queue<no>qu;
    cin>>s>>p;
    for(int i=1; i<=p; i++)
    {
        int x,y;
        cin>>x>>y;
        xx[i]=x;
        yy[i]=y;
    }
    for(int i=1; i<=p; i++)
        for(int j=i+1; j<=p; j++)
        {
            mp.x=i;
            mp.y=j;
            mp.d=dmath(xx[i],yy[i],xx[j],yy[j]);

            qu.push(mp);
        }
    int l=0;
    dou res=-1.0;
    for(int i=1; i<=p; i++) d[i]=i;

// cout<<qu.size()<<endl;

    int k=0;
    while(k<p-s)
    {
        mp=qu.top();
        qu.pop();
        if(merge(mp.x,mp.y))
        {
            k++;

// printf("%.2lf ",mp.d);

            res=max(res,mp.d);
        }
    }
    printf("%.2lf\n",res);
}

return 0;
}

相关文章
|
6月前
|
消息中间件 Kubernetes NoSQL
动态规划-状态压缩、树形DP问题总结
动态规划-状态压缩、树形DP问题总结
|
算法
【学会动态规划】最小路径和(9)
【学会动态规划】最小路径和(9)
41 0
|
机器学习/深度学习 算法
【动态规划刷题 9】最大子数组和 III && 环形子数组的最大和
【动态规划刷题 9】最大子数组和 III && 环形子数组的最大和
|
测试技术
【动态规划刷题 10】最大子数组和 III && 环形子数组的最大和
【动态规划刷题 10】最大子数组和 III && 环形子数组的最大和
|
6月前
|
算法 定位技术
【leetcode】剑指 Offer II 105. 岛屿的最大面积-【深度优先DFS】
【leetcode】剑指 Offer II 105. 岛屿的最大面积-【深度优先DFS】
72 0
|
6月前
|
算法
leetcode-675:为高尔夫比赛砍树 (最短路径算法bfs,dijkstra,A*)
leetcode-675:为高尔夫比赛砍树 (最短路径算法bfs,dijkstra,A*)
56 0
|
6月前
Poj 3255(dijkstra求次短路)
Poj 3255(dijkstra求次短路)
40 0
poj 1185 炮兵阵地 (状态压缩dp)
如果你是刚刚开始做状态压缩dp,我建议你先看看 poj 3254 Corn Fields 这是一道比这一题更简单,更容易入门的题目。 还有在代码中我用了一个很巧妙的方法求一个数二进制数中1的个数 具体请看我博客中 x& (x - 1)==0 这篇文章 链接 。
39 1
poj 1990 MooFest 树状数组
题意就是有N头牛,每头牛都有一个坐标和声调值(x, v),两头牛之间通讯要花费的能量是他们的距离乘以最大的一个音调值,现在要任意两头牛之间都相互通讯一次,求总共需要花费多少能量?
47 0
|
人工智能 算法 搜索推荐
LeetCode 周赛 338,贪心 / 埃氏筛 / 欧氏线性筛 / 前缀和 / 二分查找 / 拓扑排序
大家好,我是小彭。 上周末是 LeetCode 第 338 场周赛,你参加了吗?这场周赛覆盖的知识点很多,第四题称得上是近期几场周赛的天花板。
109 0