参考红宝书

题目链接

对除 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. 阿里云centos7[linux]安装nginx

    标题 说明 服务器版本 Centos7 x64 nginx版本 1.19.6 作者 walton 一.准备 创建安装包目录并进入 mkdir /usr/dev/nginx cd /usr/dev/ng ...

  2. 配置Oracle数据库和监听随Linux系统自启动【转】

     配置Oracle数据库和监听随Linux系统自启动     在某些情况下需要在Linux操作系统上提供一种无人值守的随机启动Oracle的功能,目的也许仅仅是为了帮助那些对Oracle细节非常不关心 ...

  3. 非root用户安装centos的jdk

    1. 下载linux的jdk到自定义目录(以下简称安装目录),解压. 2. 在安装目录下新建文件局部环境变量文件:bash_profile 内容为:(注意修改JAVA_HOME目录) export J ...

  4. Python 中的行向量、列向量和矩阵

    1.一维数组 一维数组既不是行向量,也不是列向量. import numpy as npa=np.array([1,2,3])print(np.shape(a))>>>(3,) 2. ...

  5. 剑指offer 面试题3:数组中重复的数字

    题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为 ...

  6. H5手机网页元素识别

  7. 开发进阶:Dotnet Core多路径异步终止

    今天用一个简单例子说说异步的多路径终止.我尽可能写得容易理解吧,但今天的内容需要有一定的编程能力.   今天这个话题,来自于最近对gRPC的一些技术研究. 话题本身跟gRPC没有太大关系.应用中,我用 ...

  8. 视频画面中实现人脸遮挡教程 - 基于 TensorFlow 实现

    在进行视频通话时,我们往往需要对画面进行一些实时分析,例如识别画面里的人.车.动物等等.这节里我们将使用时信魔方的人脸监视模块实现人脸被手部遮挡的检测,如下图所示效果: 预备知识 时信魔方的客户端使用 ...

  9. springAOP的概述及使用

    Spring AOP SpringAOP是Spring中非常重要的功能模块之一,该模块提供了面向切面编程,在事务处理,日志记录,安全控制等操作中广泛使用. SpringAOP的基本概念 AOP的概念 ...

  10. centos7安装docker、docker-compose、es7.3.0、kibana7.3.0

    一.安装docker 1.更新yum包 sudo yum update 2.卸载旧版本(如果安装过旧版本的话) sudo yum remove docker docker-common docker- ...