参考红宝书

题目链接

对除 1 号点顶点外的点集,求一次最小生成森林,对于最小生成森林的联通分量,选择最短的一条边与 1 号点相连。设此时 1 号点的度为 \(k_0\),如果 \(k_0\lt L\) 则无解 (L为1号顶点的规定度)

然后通过可行交换来增加 1 号点的度,每次尝试加入一条和 1 号点相连的边,然后删去所形成的环上面的最长边。

此题点数为 5000,对于每次交换,可以用树形DP求出所有点到 1 号点的最长边。每次选择增量最小的边去交换,直到 \(k_0\) 达到 L

在实现中的一些困难:

  1. 答案要求构成生成树的边序号,所以加边时要保留原边序号信息
  2. 树形DP要找到每个点到 根 的最长路大小,以及对应边的序号
  3. 如果一个点与根直接相连,可以把这个边序号保留下来(下面代码中用path数组保留),方便之后做替换用
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
#define dbg(x...) do { cout << "\033[32;1m" << #x <<" -> "; err(x); } while (0)
void err() { cout << "\033[39;0m" << endl; }
template<class T, class... Ts> void err(const T& arg,const Ts&... args) { cout << arg << " "; err(args...); }
const int N = 5000 + 5;
const int M = 200010;
int head[N], ver[M], nxt[M], edge[M];
int fa[N], mark[M], best[N], cand[N];
int path[N];
int n, m, k, tot;
struct Edge{
int x, y, z;
int id;
Edge(int a=0,int b=0, int c=0, int d=0):x(a),y(b),z(c),id(d){}
bool operator <(Edge b){
return z < b.z;
}
}e[M];
void add(int x, int y, int z, int id){
ver[id] = y, edge[id] = z, nxt[id] = head[x], head[x] = id;
}
void addEdge(int i){
add(e[i].x, e[i].y, e[i].z, i*2);
add(e[i].y, e[i].x, e[i].z, i*2+1);
}
int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);}
void dfs(int x, int fat){
for(int i=head[x];i;i=nxt[i]){
if(!mark[i>>1] || ver[i] == fat) continue;
int y = ver[i];
if(x == 1){// 从根出发的边,不能被替换
best[y] = -inf;
} else {
best[y] = edge[i], cand[y] = i >> 1; // 边的序号其实是 i/2
if(best[y] < best[x]){
best[y] = best[x];
cand[y] = cand[x];
}
}
dfs(y, x);
}
}
bool solve(){
sort(e + 1, e + 1 + m);
for(int i=1;i<=n;i++) fa[i] = i;
for(int i=1;i<=m;i++){
int x = e[i].x, y = e[i].y;
if(x == 1 || find(x) == find(y)) continue;
mark[e[i].id] = 1;
fa[find(x)] = find(y);
}
//按照id排序,便于之后处理
sort(e + 1, e + 1 + m, [](Edge a, Edge b){return a.id < b.id;});
int component = 0;//连通块个数
for(int i=2;i<=n;i++){
if(find(i) == i){
component ++;
best[i] = inf;
}
}
if(component > k) return false;
for(int i=1;i<=m;i++){
if(e[i].x != 1) continue;
path[e[i].y] = i;
int rt = find(e[i].y);
if(e[i].z < best[rt]){
best[rt] = e[i].z;
cand[rt] = i;
}
}
for(int i=2;i<=n;i++){
if(find(i) != i) continue;
if(best[i] == inf) return false;
mark[cand[i]] = 1;
}
for(int i=1;i<=m;i++){
if(mark[i]) addEdge(i);
}
while(component < k){
dfs(1, 0); //树形DP
int mx = inf, tcand = 0;
for(int i=2;i<=n;i++){
if(path[i] == 0 || best[i] == -inf) continue;
if(e[path[i]].z - best[i] < mx){
mx = e[path[i]].z - best[i];
tcand = i;
}
}
if(mx == inf) return false;
mark[cand[tcand]] = 0;
mark[path[tcand]] = 1;
addEdge(path[tcand]);
component ++;
}
printf("%d\n", n-1);
for(int i=1;i<=m;i++){
if(mark[i]) printf("%d ", i);
}
return true;
}
int main(){
scanf("%d%d%d", &n, &m, &k);
for(int i=1;i<=m;i++){
int x, y, z;scanf("%d%d%d", &x, &y, &z);
if(x > y) swap(x, y);
e[i] = Edge(x, y, z, i);
}
if(!solve()) puts("-1");
return 0;
}

CF-125E MST Company (单度限制最小生成树)的更多相关文章

  1. CodeForces 125E MST Company

    E. MST Company time limit per test 8 seconds memory limit per test 256 megabytes input standard inpu ...

  2. CODEFORCES 125E MST Company 巧用Kruskal算法

    题意:给定一个带权边无向图,求最小生成树,且满足第一个节点的度为固定的k 无解则输出-1 数据规模: 节点数n和限制k<=5000 边数m<=10^5 时限8sec 思路: 首先时限比较宽 ...

  3. 【CF125E】MST Company(凸优化,最小生成树)

    [CF125E]MST Company(凸优化,最小生成树) 题面 洛谷 CF 题解 第一眼看见就给人丽洁姐那道\(tree\)一样的感觉. 那么二分一个权值,加给所有有一个端点是\(1\)的边, 然 ...

  4. luogu CF125E MST Company wqs二分 构造

    LINK:CF125E MST Company 难点在于构造 前面说到了求最小值 可以二分出斜率k然后进行\(Kruskal\) 然后可以得到最小值.\(mx\)为值域. 得到最小值之后还有一个构造问 ...

  5. 【AtCoder3611】Tree MST(点分治,最小生成树)

    [AtCoder3611]Tree MST(点分治,最小生成树) 题面 AtCoder 洛谷 给定一棵\(n\)个节点的树,现有有一张完全图,两点\(x,y\)之间的边长为\(w[x]+w[y]+di ...

  6. CF F. MST Unification (最小生成树避圈法)

    题意 给一个无向加权联通图,没有重边和环.在这个图中可能存在多个最小生成树(MST),你可以进行以下操作:选择某条边使其权值加一,使得MST权值不变且唯一.求最少的操作次数. 分系:首先我们先要知道为 ...

  7. 度限制最小生成树 POJ 1639 贪心+DFS+prim

    很好的解题报告: http://blog.csdn.net/new_c_yuer/article/details/6365689 注意两点: 1.预处理环中权值最大的边···· 2.可以把去掉度限制后 ...

  8. POJ 1679 The Unique MST (次小生成树 判断最小生成树是否唯一)

    题目链接 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. De ...

  9. Solution -「CF 1025G」Company Acquisitions

    \(\mathcal{Description}\)   Link.   \(n\) 个公司,每个公司可能独立或者附属于另一个公司.初始时,每个公司附属于 \(a_i\)(\(a_i=-1\) 表示该公 ...

随机推荐

  1. Spring中的@Valid 和 @Validated注解你用对了吗

    1.概述 本文我们将重点介绍Spring中 @Valid和@Validated注解的区别 . 验证用户输入是否正确是我们应用程序中的常见功能.Spring提供了@Valid和@Validated两个注 ...

  2. Java开发手册之异常日志

    1.捕获异常的时候,有一种特殊情况,就是方法体内部所抛出的并不是Exception而是Error,这个时候,上层方法捕获Exception就会失败.所以在某些场合需要捕获更高一级别的Throwable ...

  3. 【Java】Jsoup爬虫,一个简单获取京东商品信息的小Demo

    简单记录 - Jsoup爬虫入门实战 数据问题?数据库获取,消息队列中获取中,都可以成为数据源,爬虫! 爬取数据:(获取请求返回的页面信息,筛选出我们想要的数据就可以了!) 我们经常需要分析HTML网 ...

  4. 攻防世界—pwn—guess_num

    题目分析 checksec检查文件保护机制 这个结果看的我满是问号??? \n ida分析程序 是一个猜数字的游戏,需要全部输入正确才能得到flag 根据大佬的wp得出一下内容 先使用srand()进 ...

  5. 集成 12 种协议、可于 USBC 端口的快充协议芯片IP2188

    1. 特性  支持 12 种 USB 端口快充协议  支持 USB TypeC PD2.0/PD3.0/PPS DFP 协议  支持多种充电协议(QC3.0/QC2.0,FCP,SCP, AFC,MT ...

  6. 解决MyBatis-Plus 3.3.1中自动生成代码tinyint(1)无法自动转换为Boolean 的办法

    解决方法 1.在测试类中新建一个类MySqlTypeConvertCustom,继承MySqlTypeConvert并实现ITypeConvert后覆盖processTypeConvert方法. 2. ...

  7. 如何创建一个Java项目

    目录 新建项目 项目信息配置 创建Java类 编译和运行 新建项目 首先双击eclipse进入到eclipse页面. 菜单"File"下的"New"里" ...

  8. 邮箱发送API .Net

    调用QQ邮箱发送邮件接口,完成QQ邮箱发送邮件.步骤如下: 1.开启POP3/SMTP服务 2.点过之后会让你验证一下密保或者发送一条短信 3.验证过后会弹出一个开启POP3/SMTP服务的授权码,这 ...

  9. Ajax编程基础

    目录 Ajax编程基础 传统网站中存在的问题 Ajax概述 Ajax的应用场景 Ajax的运行环境 Ajax运行原理及实现 Ajax运行原理 Ajax的实现步骤 1.创建Ajax对象 2.告诉Ajax ...

  10. 【Windows】Win10家庭版启用组策略gpedit.msc

    [前言] 大家都认为,Windows 10家庭版中并不包含组策略,其实不然,它是有相关文件的,只是不让你使用而已.那么我们让系统允许你使用就好了. [操作步骤] 1.首先你需要在桌面上新建一个txt文 ...