zoukankan      html  css  js  c++  java
  • 【洛谷P5633】最小度限制生成树

    题目

    题目链接:https://www.luogu.com.cn/problem/P5633
    给你一个有 (n) 个节点,(m) 条边的带权无向图,你需要求得一个生成树,使边权总和最小,且满足编号为 (s) 的节点正好连了 (k) 条边。
    (nleq 5 imes 10^4,mleq 5 imes 10^5,kleq 100)

    思路

    假设我们直接求出了最小生成树,此时最小生成树上有 (t) 条边是连接 (s) 点的。不妨设 (t<k)
    如果此时加入一条没被选择的连接 (s) 的边,必然会形成一个环,那么我们找到环上权值最大的不连接 (s) 的边删去。重复上述过程就可以得到一个有 (k) 条边连接 (s) 的生成树。
    设恰好有 (i) 条连接 (s) 的边时最小生成树权值和为 (s_i),那么我们可以把 ((i,s_i)) 看做一个二维平面上的点。连接这些点之后必然是一个下凸壳。因为在刚刚删去黑边加入白边的过程中,为了让生成树权值尽量小,一定是选择差值最小的先加入。
    于是就可以采用 wqs 二分解决这个问题了。
    时间复杂度 (O(mlog mlog V)),其中 (V) 是边权最大值。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=50010,M=500010;
    int n,m,s,k,cnt,maxd,father[N];
    ll sum,ans;
    
    struct edge
    {
    	int u,v,dis;
    }e[M];
    
    bool cmp(edge x,edge y)
    {
    	return x.dis<y.dis;
    }
    
    int find(int x)
    {
    	return x==father[x]?x:father[x]=find(father[x]);
    }
    
    void kruskal()
    {
    	sort(e+1,e+1+m,cmp);
    	for (int i=1;i<=m;i++)
    	{
    		int x=find(e[i].u),y=find(e[i].v);
    		if (x!=y)
    		{
    			if (e[i].u==s || e[i].v==s) cnt++;
    			sum+=e[i].dis; father[x]=y; 
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%d%d%d",&n,&m,&s,&k);
    	for (int i=1;i<=n;i++) father[i]=i;
    	for (int i=1;i<=m;i++)
    	{
    		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].dis);
    		if (e[i].u!=s && e[i].v!=s) 
    			father[find(e[i].u)]=find(e[i].v),cnt++;
    		maxd=max(maxd,e[i].dis);
    	}
    	if (cnt+k<n-1) { cout<<"Impossible"; return 0; }
    	int l=-maxd,r=maxd,mid;
    	ans=-1;
    	while (l<=r)
    	{
    		mid=(l+r)>>1;
    		for (int i=1;i<=m;i++)
    			if (e[i].u==s || e[i].v==s) e[i].dis+=mid;
    		cnt=sum=0;
    		for (int i=1;i<=n;i++) father[i]=i;
    		kruskal();
    		if (cnt>=k) l=mid+1,ans=sum-1LL*mid*k;
    			else r=mid-1;
    		for (int i=1;i<=m;i++)
    			if (e[i].u==s || e[i].v==s) e[i].dis-=mid;
    	}
    	if (ans!=-1) cout<<ans;
    		else cout<<"Impossible";
    	return 0;
    }
    
  • 相关阅读:
    ORACLE 查看进程数,已执行任务数, 剩余任务数,删除指定任务
    ORACLE 收集统计整个用户数据
    解决Hystrix dashboard Turbine 一直 Loading…… 及其他坑
    利用 Maven 构造 Spring Cloud 微服务架构 模块使用 spring Boot构建
    AES加解密
    JAVA POI XSSFWorkbook导出扩展名为xlsx的Excel,附带weblogic 项目导出Excel文件错误的解决方案
    JAVA 文件的上传下载
    shell启停服务脚本模板
    JAVA 设计模式之 原型模式详解
    JAVA 设计模式之 工厂模式详解
  • 原文地址:https://www.cnblogs.com/stoorz/p/15008443.html
Copyright © 2011-2022 走看看