B - Super Mancunian HackerRank - super-mancunian并查集与最小生成树

题目大意:求最小生成树但可以减去一条边(当然要减最大的那个了)。
思路:可以用并查集来存图,找出最大值,用是否为父亲节点来判断是否为新的点。再次遍历一遍,pre[]数组置-1,如果有先判断是否产生环(判断pre[]是否相等)。再判断是否大于等于最大值,是的话就多出一种。否则就u的父亲节点归到v的父亲节点的门下,继续遍历。

在这里插入图片描述

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=5e5+10;
int head[maxn],cnt;
int want[maxn],pos,max1;
int n,m,k,ans,pre[maxn];
struct node
{
    int u,v,w;
} a[maxn];
struct nod
{
    int to,w,next;
}e[maxn];
void addedge(int u,int v,int w)
{
    e[cnt].to=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
int cmp(node a,node b)
{
    return a.w<b.w;
}
int root(int x)
{
    if(x!=pre[x])
    {
      pre[x]=root(pre[x]);
    }
    return pre[x];
}
void join(int a,int b,int w)
{
    int x=root(a);
    int y=root(b);
    if(x!=y)//不相等就代表时加入了带有新点的边
    {
        pre[x]=y;
        want[pos++]=w;
        max1=w;
        k++;
        ans+=w;
    }
}
 signed main()
 {
     memset(head,-1,sizeof(head));
     cin>>n>>m;
     for(int i=1;i<=n;i++)
     {
         pre[i]=i;
     }
     for(int i=0;i<m;i++)
     {
         int u,v,w;
         scanf("%lld%lld%lld",&u,&v,&w);
         a[i].u=u;
         a[i].v=v;
         a[i].w=w;
     }
     sort(a,a+m,cmp);
     int i=0;
     while(k<n-1)
     {
         join(a[i].u,a[i].v,a[i].w);
         i++;
     }
     for(int i=1;i<=n;i++)
     {
         pre[i]=i;
     }
     int  tot=0;
     for(int i=0;i<m;i++)
     {
         if(root(a[i].u)!=root(a[i].v))//防止成环
         {
             if(a[i].w>=max1)
             {
                tot++;
             }
             else
             {
                 pre[root(a[i].u)]=root(a[i].v);
             }
         }
     }
     cout<<ans-max1<<" "<<tot<<endl;
     return 0;
 }
发布了9 篇原创文章 · 获赞 0 · 访问量 169

猜你喜欢

转载自blog.csdn.net/luoxutimberjack/article/details/104303560