51nod1640-最小生成树&二分|性质-天气晴朗的魔法

来源:互联网 发布:hive sql create 编辑:程序博客网 时间:2024/05/22 03:10

https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1640
首先要求生成树的最大边最小,然后再要求生成树权值和最大。。
开始写了一个二分。。明显是没有理解krusal。 开始写的是这样。。
这里写图片描述。。
每次生成的mst都是一样的。。(我边是从大到小的。。)如果只有最大的边可以二分成功,其他的都失败。。
想用上一次二分最短路最大值那种方法的。。尴尬。。(用最大值卡边的大小)。我这样离线维护max,mst是不会变的。不能做到每次二分都根据最大值来生成不同的mst。正确的做法是

#include <bits/stdc++.h>using namespace std;/*二分+mst把。*/typedef long long ll;const int MAXN=1e5+300;//最大点数const int MAXM=250005;//最大边数int F[MAXN];//并查集使用struct Edge{    int u,v;    ll w;}edge[MAXM];//储存边的信息,包括起点/终点/权值int tol;//边数,加边前赋值为0void addedge(int u,int v,ll  w){    edge[tol].u=u;    edge[tol].v=v;    edge[tol++].w=w;}bool cmp(Edge a,Edge b)//排序函数,边按照权值从小到大排序{    return a.w>b.w;}int Find(int x){    if(F[x]==-1)        return x;    else        return F[x]=Find(F[x]);}typedef long long ll;ll Kruskal(int n,ll  maxcos)//传入点数,返回最小生成树的权值,如果不连通返回-1{    memset(F,-1,sizeof(F));    sort(edge,edge+tol,cmp);    int cnt=0;//计算加入的边数    ll  ans=0;    ll max2=-1;    for(int i=0;i<tol;i++)    {        int u=edge[i].u;        int v=edge[i].v;        ll w=edge[i].w;        int t1=Find(u);        int t2=Find(v);        if(w>maxcos) continue;        if(t1!=t2)        {            ans+=w;            F[t1]=t2;            cnt++;        }        max2=max(max2,1ll*w);        if(cnt==n-1)            break;    }    //if(maxcos<0)return -1;    //if(max2>maxcos) return -1;    if(cnt<n-1)        return -1;//不连通    else        return ans;}int main(){   int m,n,a,b;ll c;    while(~scanf("%d%d",&m,&n)){          ll max1=-1;          ll min1=1e16;          for(int i=0;i<n;i++){             scanf("%d%d%lld",&a,&b,&c);             addedge(a,b,c);             max1=max(max1,c);             min1=min(min1,c);          }          ll  l=0;         ll r=max1*2;         //cout<<Kruskal(m,5)<<endl;          ll ans=0;          while(l<r){              ll mid=(l+r)/2;              ll dd=Kruskal(m,mid);              if(dd!=-1){                 ans=dd;                 //cout<<mid<<endl;                 r=mid;              }              else                l=mid+1;          }          printf("%lld\n",ans);    }    return 0;}

② 看注释把。那么长

#include <bits/stdc++.h>using namespace std;/*我脑子是怎么想的,这道题的思路 明明是二分维护一个最大值。然后再这个限制内建造一个mst。如果能建造一个mst的话那么就建立。我却写的是 二分维护一个最大值然后,注意是然后! 建造一个mst.如果这个mst的最大边大于维护的这个值。就不可以!!!注意注意! ,竟然没有发现这样建造的mst只有一个,我tm。。一个图的所有生成树中的最小的最大边,就是他的mst上的最大边。所以,朋友们,我们只需要计算即可*/int m,n;const int maxn=2e5+200;typedef long long ll;struct Node{   int from;int to,cost;}edge[maxn];int fa[maxn];int tol;void add(int a,int b,int c){     edge[tol].to=b;     edge[tol].cost=c;     edge[tol++].from=a;}int find1(int a){    if(fa[a]==a) return a;     return fa[a]=find1(fa[a]);}int unite(int x,int y){     int a=find1(x);     int b=find1(y);     if(a!=b){        fa[a]=b;     }}void init(){   tol=0;   for(int i=0;i<maxn;i++)      fa[i]=i;}bool cmp2(Node a,Node b ){    return a.cost>b.cost;}bool cmp1(Node a,Node b){    return a.cost<b.cost;}int main(){   int m,n,a,b,c;    while(~scanf("%d%d",&m,&n)){          init();          for(int i=0;i<n;i++){              scanf("%d%d%d",&a,&b,&c);              add(a,b,c);          }          sort(edge,edge+tol,cmp1);          int val=-1;          for(int i=0;i<tol;i++){              int u=find1(edge[i].from);              int v=find1(edge[i].to);              int sum=edge[i].cost;              if(u!=v){                unite(u,v);                val=max(sum,val);              }          }          for(int i=0;i<maxn;i++){              fa[i]=i;          }          ll all=0;          sort(edge,edge+tol,cmp2);         for(int i=0;i<tol;i++){              int u=find1(edge[i].from);              int v=find1(edge[i].to);              int sum=edge[i].cost;              if(sum>val) continue;              if(u!=v){                unite(u,v);                all+=sum;              }          }          printf("%lld\n",all);    }    return 0;}
原创粉丝点击