zoukankan      html  css  js  c++  java
  • 题解 CF1095F 【Make It Connected】

    题目链接

    luogu题目链接

    (因为自己想了很久都没有想出来,所以记录下来)

    题目大意:

    给你n个点,每个点有一个权值(a[i]),已知连接两点的代价为(a[i]+a[j]),现在还有其他的(m)种连接方法,连接(x,y)的代价为(w),求出让这个图连通的最小代价.

    我们看到了求出让这个图连通的最小代价.

    那明显就是最小生成树了啊。

    但是如果我们常规建边,那么需要(n imes(n-1)+m)的时间复杂度,而数据强度是:

    [n <= 2 imes10^5 ]

    所以(n^2)的建边是要炸掉的。

    所以我们需要思考一些可以帮助我们优化算法的性质。

    1. 无用边

    对于那个(n imes(n-1))的边,我们很明显看得出来是完全图。

    那么完全图的最小生成树是怎样的呢?

    很显然是点值最小的点连接其他所有的点(俗称菊花图

    而其他边在增加了m条边后还有没有用?

    假设有一条边(<x,y>)是有用的,那么其权值为(val[x]+val[y]),而我们根据最小生成树的定义可以知道,在最小生成树里,这两个点要么都没有和最小点(我们将其设为minn)有边,要么只有一个点和minn有边(因为如果两个点都右边的话就形成图了)

    (默认(val[x]<val[y])

    当都没有连边时:

    我们将(<x,y>)这条边删去,再将minn连向其中一个点,那么最小生成树中全职的变化是:

    [-val[x]-val[y]+val[minn]+val[x/y] ]

    我们可以轻松看出是负数,所以这才是真正的最小生成树。

    当有连边时:

    和上面一样。

    所以我们可以知道剩下的边对于最终的最小生成树都没有贡献。所以我们只需要加入(n-1)个边,于是

    [n imes(n-1)---->n-1 ]

    时间和空间复杂度大大降低,于是此题可做。

    [Show;my;code;! ]

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define ri register int
    #define Starseven main
    #define ll long long
    using namespace std;
    const int N=2e5+20;
    int n,m,fa[N];
    ll ans;
    
    struct node{
    	ll val;
    	int id;
    }num[N];
    
    bool cmp(const node &a,const node &b){
    	return a.val<b.val;
    }
    
    struct nod{
    	int from,to;
    	ll cos;
    }tr[N<<1];
    int cnt;
    
    bool cmd(const nod &a,const nod &b){
    	return a.cos<b.cos;
    }
    
    void Add(int x,int y,ll va){
    	tr[++cnt].from=x;tr[cnt].to=y;tr[cnt].cos=va;
    	return ;
    }
    
    int Find(int x){
    	if(fa[x]==x) return x;
    	else return fa[x]=Find(fa[x]);
    }
    
    int Starseven(void){
    	cin>>n>>m;
    	for(ri i=1;i<=n;i++) num[i].id=fa[i]=i,cin>>num[i].val;
    	sort(num+1,num+1+n,cmp);
    	for(ri i=2;i<=n;i++) Add(num[1].id,num[i].id,num[1].val+num[i].val);
    	for(ri i=1;i<=m;i++){
    		int x,y;ll va;
    		cin>>x>>y>>va;
    		Add(x,y,va);
    	}
    	sort(tr+1,tr+1+cnt,cmd);
    	int judge=0;
    	for(ri i=1;i<=cnt;i++){
    		int fx=Find(tr[i].from),fy=Find(tr[i].to);
    		if(fx==fy) continue;
    		fa[fx]=fy;
    		ans+=tr[i].cos;
    		judge++;
    		if(judge==n-1) break;
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

    后记:

    我最开始的时候想到了要和最小点连边,但是我没有在最后想到最小生成树,而是想到了一个一个m的边加入,然后判断是否能够替换,现在想来我就是在没有Kus的基础上想最小生成树,看来我对于图论的知识点还不够熟悉,所以还要加强学习!

  • 相关阅读:
    谁说固态硬盘没容量?4TB诞生、明年8TB!
    微软.NET Framework 4.5.2 RTM正式版
    Chrome 应用推荐
    MS14-021: Internet Explorer 安全更新: 2014 年 5 月 1 日
    百视通与微软共同宣布9月在华发布Xbox One
    支付宝5月4日起将停止收款主页业务 保留三种收款方式
    Chrome 应用推荐
    为什么《舌尖上的中国》让你欲罢不能?
    求连续子数组的最大乘积
    损失函数与代价函数区别
  • 原文地址:https://www.cnblogs.com/starseven/p/13052401.html
Copyright © 2011-2022 走看看