51nod 1640 天气晴朗的魔法 克鲁斯卡尔

来源:互联网 发布:海通期货软件 编辑:程序博客网 时间:2024/06/05 17:32

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1640
思路:题目要求求最大生成树,并且对最大边有限制,先按照克鲁斯卡尔算法求出生成最小成树过程中,加入生成树的最大边。这条边是能构成生成树最低要求的边,记作maxw,符合题目意思了,然后求最大生成树,求法与最小生成树的过程相反,将大于maxw的边剔除,从大到小取边加入边集合,知道所有点都到生成树集合中。
一开始用个-1标记最大生成树不存在,生成树的权值可以为负,一直错在一个样例上。还有就是并查集竟然忘记路径压缩(╥╯^╰╥)

#include<cstdio>// 最大生成树 #include<queue>#include<iostream>#include<vector>#include<map>#include<cstring>#include<string>#include<set>#include<stack>#include<algorithm>#define cle(a) memset(a,0,sizeof(a))#define inf(a) memset(a,0x3f,sizeof(a))#define ll long long#define Rep(i,a,n) for(int i=a;i<=n;i++)using namespace std;const int INF = ( 2e9 ) + 2;const ll maxn = 2e5+10;ll maxw,flag;struct edge{    int u,v;    ll w;};vector<edge> e;int f[maxn];bool cmp(edge a,edge b){    return a.w<b.w;}int Find(int x){    return f[x]==x?x:f[x]=Find(f[x]);}ll Kruscal_1(int n){    ll ans=0;    for(int i=1;i<=n;i++)f[i]=i;    sort(e.begin(),e.end(),cmp);    for(int i=0,L=e.size();i<L;i++)    {        ll w=e[i].w;        int u=e[i].u,v=e[i].v;        int xx=Find(u);        int yy=Find(v);        if(xx!=yy)        {            ans+=w;            f[xx]=yy;            if(maxw<w)maxw=w;        }    }    return ans;}ll Kruscal_2(int n,int maxw){    ll num=0,ans=0;    for(int i=1;i<=n;i++)f[i]=i;    for(int i=e.size()-1;i>=0;i--)    {        ll w=e[i].w;        if(w>maxw)continue;        int u=e[i].u,v=e[i].v;        int xx=Find(u);        int yy=Find(v);        if(xx!=yy)        {            ans+=w;            num++;            f[xx]=yy;            if(maxw<w)maxw=w;        }    }    if(num!=n-1) flag = 1;    else return ans;}int main(){    int n,m;    scanf("%d%d",&n,&m);    for(int i=0;i<m;i++)    {        int u,v;        ll w;        scanf("%d%d%lld",&u,&v,&w);        e.push_back(edge{u,v,w});    }    maxw=-1,flag=0;    ll ans1=Kruscal_1(n);    ll ans2=Kruscal_2(n,maxw);    if(flag)printf("%lld\n",ans1);    else    printf("%lld\n",ans2);}/*4 61 2 31 3 11 4 72 3 42 4 53 4 6*/