2022.2.16

重新看了下最小生成树

kruskal算法

【1】先将图中带权的(两点)全部得到(放在结构体中)

【2】然后按权值大小排序(从小到大)

【3】将点与点连成边(用并查集判断是否有环)

最小生成树(模板题)

思路:和上面一样

#include<bits/stdc++.h>
using namespace std;
struct edge
{
    int x;
    int y;
    int z;
} edge[200010];
int father[5010];
int n,m;
void fastsort(int left,int right)
{
    int i=left,j=right;
    int mid=edge[(left+right)/2].z;
    if(left>=right)
        return;
    while(i<=j)
    {
        while(edge[j].z>mid)
            j--;
        while(edge[i].z<mid)
            i++;
        if(i<=j)
        {
            struct edge temp=edge[i];
            edge[i]=edge[j];
            edge[j]=temp;
            j--;
            i++;
        }
    }
    fastsort(left,j);
    fastsort(i,right);
}

//找祖宗
int find_root(int x)
{
    if(x!=father[x])
        father[x]=find_root(father[x]);
    return father[x];
}

int main()
{
    int ans=0;
    long long sum=0;
    cin>>n>>m;
    //将边输入
    for(int i=1; i<=m; i++)
    {
        cin>>edge[i].x>>edge[i].y>>edge[i].z;
    }
    fastsort(1,m);
//    for(int i=1;i<=m;i++)
//        cout<<edge[i].x<<' '<<edge[i].y<<' '<<edge[i].z<<endl;
    //并查集
    for(int i=1; i<=n; i++)
        father[i]=i;
    for(int i=1; i<=m; i++)
    {
        int x_root=find_root(edge[i].x);
        int y_root=find_root(edge[i].y);
        if(x_root!=y_root)
        {
            sum+=edge[i].z;
            father[x_root]=y_root;
            ans++;
            if(ans==n-1)
                break;
        }
    }
//    for(int i=1;i<=m;i++)
//        if(father[i]==i)
//            ans++;
//    if(ans>1)
    if(ans!=n-1)
        cout<<"orz"<<endl;
    else
        cout<<sum<<endl;
    return 0;
}

拆地毯

思路:和上面唯一不同的是这里要求最大值,所以是从大到小排列

#include<bits/stdc++.h>
using namespace std;
int n,m,k;
struct edge
{
    int u,v,w;
}edge[100005];
int father[100005];
void fastsort(int left,int right)
{
    int i=left,j=right;
    int mid=edge[(left+right)/2].w;
    if(left>=right)
        return;
    while(i<=j)
    {
        while(edge[j].w<mid)
            j--;
        while(edge[i].w>mid)
            i++;
        if(i<=j)
        {
            struct edge temp=edge[i];
            edge[i]=edge[j];
            edge[j]=temp;
            j--;
            i++;
        }
    }
    fastsort(left,j);
    fastsort(i,right);
}
int find_root(int x)
{
    if(father[x]!=x)
        father[x]=find_root(father[x]);
    return father[x];
}
int main()
{
    int ans=0,sum=0,Max=0;
    cin>>n>>m>>k;
    for(int i=1;i<=m;i++)
    {
        cin>>edge[i].u>>edge[i].v>>edge[i].w;
    }
    //从大到小排序
    fastsort(1,m);
    for(int i=1;i<=n;i++)
        father[i]=i;
    for(int i=1;i<=m;i++)
    {
        int u_root=find_root(edge[i].u);
        int v_root=find_root(edge[i].v);
        if(u_root!=v_root)
        {
            sum+=edge[i].w;
            father[u_root]=v_root;
            ans++;
            if(ans==k)
                break;
        }
    }
    cout<<sum<<endl;
    return 0;
}



口袋的天空

思路:和模板又一样了

#include<bits/stdc++.h>
using namespace std;
int n,m,k;
int father[10005];
struct spun
{
    int x,y,l;
}candy[10005];
void fastsort(int left,int right)
{
    int i=left,j=right;
    int mid=candy[(left+right)/2].l;
    if(left>=right)
        return ;
    while(i<=j)
    {
        while(candy[j].l>mid)
            j--;
        while(candy[i].l<mid)
            i++;
        if(i<=j)
        {
            struct spun temp=candy[i];
            candy[i]=candy[j];
            candy[j]=temp;
            j--;
            i++;
        }
    }
    fastsort(left,j);
    fastsort(i,right);
}
int find_root(int x)
{
    if(father[x]!=x)
        father[x]=find_root(father[x]);
    return father[x];
}
int main()
{
    int ans=0,sum=0;
    cin>>n>>m>>k;
    for(int i=1;i<=m;i++)
    {
        cin>>candy[i].x>>candy[i].y>>candy[i].l;
    }
    fastsort(1,m);
    for(int i=1;i<=n;i++)
    {
        father[i]=i;
    }
    for(int i=1;i<=m;i++)
    {
        int x_root=find_root(candy[i].x);
        int y_root=find_root(candy[i].y);
        if(x_root!=y_root)
        {
            sum+=candy[i].l;
            father[x_root]=y_root;
            ans++;
            if(ans==n-k)
                break;
        }
    }
    if(ans==n-k)
        cout<<sum<<endl;
    else
        cout<<"No Answer"<<endl;
    return 0;
}

无线通讯网

思路:这个题和前面题的不同在于这个题他的权值需要自己求

题目中给出了点的坐标,我们只要将两点之间的距离(距离公式)求出来,就又是模板题了

注意:数组要开大一点,要注意 double 型的使用是在哪些地方

#include<bits/stdc++.h>
using namespace std;
int s,p,cnt;
int father[501];
//坐标
struct coordinete
{
    int x,y;
}coordinate[501];

struct edge
{
    int u,v;
    //注意这个double
    double w;
}edge[400005];

//注意这里的w是double
void add(int u,int v,double w)
{
    cnt++;
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].w=w;
}
void fastsort(int left,int right)
{
    int i=left,j=right;
    double mid=edge[(left+right)/2].w;
    if(left>=right)
        return ;
    while(i<=j)
    {
        while(edge[j].w>mid)
            j--;
        while(edge[i].w<mid)
            i++;
        if(i<=j)
        {
            struct edge temp=edge[i];
            edge[i]=edge[j];
            edge[j]=temp;
            j--;
            i++;
        }
    }
    fastsort(left,j);
    fastsort(i,right);
}
int find_root(int x)
{
    if(father[x]!=x)
        father[x]=find_root(father[x]);
    return father[x];
}
int main()
{
    int ans=0;
    double sum=0;
    cin>>s>>p;
    for(int i=1;i<=p;i++)
    {
        cin>>coordinate[i].x>>coordinate[i].y;
    }
    for(int i=1;i<=p;i++)
    {
        for(int j=i+1;j<=p;j++)
        {
            //double
            double w=sqrt((coordinate[i].x-coordinate[j].x)*(coordinate[i].x-coordinate[j].x)+(coordinate[i].y-coordinate[j].y)*(coordinate[i].y-coordinate[j].y));
            add(i,j,w);
        }
    }
    fastsort(1,cnt);
    for(int i=1;i<=p;i++)
        father[i]=i;
    for(int i=1;i<=cnt;i++)
    {
        int u_root=find_root(edge[i].u);
        int v_root=find_root(edge[i].v);
        if(u_root!=v_root)
        {
            //注意这里不是把这个加上去而是让它等于到那里的最大值
            sum=edge[i].w;
            father[u_root]=v_root;
            ans++;
            if(ans==p-s)
                break;
        }
    }
    printf("%.2lf\n",sum);
    return 0;
}

P2872 Building Roads s

思路:和无线通讯网挺像的,就都是double型,还都需要求权值

            但是这个题中输入的m条边是相对于后面连接好的(这里可用并查集表示连好,也可以用权值为0表示)

就离谱:这个题用sort能过,自己写的fastsort过不了(可能是还是比sort慢了,嘤嘤嘤)

#include<bits/stdc++.h>
using namespace std;
int n,m,cnt;
int father[1001];
struct coordinate
{
    int x,y;
}c[1001];
struct edge
{
    int u,v;
    double w;
}edge[5000001];
void add(int u,int v,double w)
{
    cnt++;
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].w=w;
}
bool cmp(struct edge a,struct edge b)
{
    return a.w<b.w;
}
int find_root(int x)
{
    if(father[x]!=x)
        father[x]=find_root(father[x]);
    return father[x];
}
int main()
{
    int ans=0;
    double sum=0;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>c[i].x>>c[i].y;
        father[i]=i;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            double w=sqrt((double)(c[i].x-c[j].x)*(c[i].x-c[j].x)+(double)(c[i].y-c[j].y)*(c[i].y-c[j].y));
            add(i,j,w);
        }
    }
    for(int i=1;i<=m;i++)
    {
        int u,v;
        cin>>u>>v;
        int uroot=find_root(u);
        int vroot=find_root(v);
        father[uroot]=vroot;
    }
    sort(edge+1,edge+1+cnt,cmp);
    for(int i=1;i<=cnt;i++)
    {
        int uroot=find_root(edge[i].u);
        int vroot=find_root(edge[i].v);
        if(uroot!=vroot)
        {
            sum+=edge[i].w;
            father[uroot]=vroot;
            ans++;
            //n个点即共有n-1条边,但其中的m条已经连接好了
            if(ans==n-1-m)
                break;
        }
    }
    printf("%.2lf\n",sum);
    return 0;
}

自己写的过不了的快排:(TLE)

#include<bits/stdc++.h>
using namespace std;
int n,m,cnt;
int father[1001];
struct coordinate
{
    int x,y;
} c[1001];
struct edge
{
    int u,v;
    double w;
} edge[1000001];
int find_root(int x)
{
    if(x==father[x])
    {
        return x;
    }
    return father[x]=find_root(father[x]);
}
void fastsort(int left,int right)
{
    int i=left,j=right;
    int mid=edge[(left+right)/2].w;
    if(left>=right)
        return;
    while(i<=j)
    {
        while(edge[j].w>mid)
            j--;
        while(edge[i].w<mid)
            i++;
        if(i<=j)
        {
            struct edge temp=edge[i];
            edge[i]=edge[j];
            edge[j]=temp;
            j--;
            i++;
        }
    }
    fastsort(left,j);
    fastsort(i,right);
}
int main()
{
    int ans=0;
    double sum=0;
    scanf("%d %d",&n,&m);
    for(int i=1; i<=n; i++)
    {
        scanf("%d %d",&c[i].x,&c[i].y);
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=i+1; j<=n; j++)
        {
            cnt++;
            edge[cnt].u=i;
            edge[cnt].v=j;
            edge[cnt].w=sqrt((double)(c[i].x-c[j].x)*(c[i].x-c[j].x)+(double)(c[i].y-c[j].y)*(c[i].y-c[j].y));
        }
    }
    fastsort(1,cnt);
    //sort(edge+1,edge+1+cnt,cmp);
    for(int i=1; i<=n; i++)
    {
        father[i]=i;
    }
    for(int i=1; i<=m; i++)
    {
        int u,v;
        scanf("%d %d",&u,&v);
        father[find_root(u)]=find_root(v);
    }
    for(int i=1; i<=cnt; i++)
    {
        int uroot=find_root(edge[i].u);
        int vroot=find_root(edge[i].v);
        if(uroot!=vroot)
        {
            father[uroot]=vroot;
            sum+=edge[i].w;
            ans++;
            if(ans==n-1-m)
                break;
        }
    }
    printf("%.2lf\n",sum);

}

 

这些题全用kruskal做了,额。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值