51nod1640-最小生成树&二分|性质-天气晴朗的魔法
2017-11-07 20:02
441 查看
https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1640
首先要求生成树的最大边最小,然后再要求生成树权值和最大。。
开始写了一个二分。。明显是没有理解krusal。 开始写的是这样。。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202011/08/83df03f55fbb86de6d421b9fe51dd712)
。。
每次生成的mst都是一样的。。(我边是从大到小的。。)如果只有最大的边可以二分成功,其他的都失败。。
想用上一次二分最短路最大值那种方法的。。尴尬。。(用最大值卡边的大小)。我这样离线维护max,mst是不会变的。不能做到每次二分都根据最大值来生成不同的mst。正确的做法是
② 看注释把。那么长
首先要求生成树的最大边最小,然后再要求生成树权值和最大。。
开始写了一个二分。。明显是没有理解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;//边数,加边前赋值为0 void 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); 4000 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; }
相关文章推荐
- 51nod 1640 天气晴朗的魔法 【二分枚举最大生成树】or【最小&&最大 生成树】
- 51nod 1640 天气晴朗的魔法 prime队列+最小生成树+最大生成树+邻接表
- 51nod 1640 天气晴朗的魔法【最小生成树概念】
- 51nod 1640 天气晴朗的魔法(最小生成树)
- 天气晴朗的魔法 大+小生成树(最大值最小)/二分
- 51nod-1640--天气晴朗的魔法(简单最小生成树)
- 51NOD 1640 天气晴朗的魔法 最小生成树 kuskal
- 51nod 1640 天气晴朗的魔法 最小生成树
- 51nod 1640 天气晴朗的魔法 最小生成树
- 1640 天气晴朗的魔法(二分最大生成树)
- 最小生成树 || ( BFS && 二分答案) —— 营救
- [51nod1640] 天气晴朗的魔法
- 51nod 1640 天气晴朗的魔法【二分+最大生成树】
- 51NOD 1640 天气晴朗的魔法(二分+最大生成树)
- 51nod 1640 天气晴朗的魔法 二分 + 克鲁斯卡算法(kruskal算法) 做复杂了
- 【bzoj1196】【二分+最小生成树】公路修建问题
- Pku acm 2075 Tangled in Cables数据结构题目解题报告(十一)最小生成树:prim算法&amp;amp;二叉查找树
- bzoj2654 tree 最小生成树+二分验证
- POJ 2421--Constructing Roads【水题 && 最小生成树 && kruskal】
- 最小生成树之 prim & kruskal