CF-125E MST Company (单度限制最小生成树)
参考红宝书
对除 1 号点顶点外的点集,求一次最小生成森林,对于最小生成森林的联通分量,选择最短的一条边与 1 号点相连。设此时 1 号点的度为 \(k_0\),如果 \(k_0\lt L\) 则无解 (L为1号顶点的规定度)
然后通过可行交换来增加 1 号点的度,每次尝试加入一条和 1 号点相连的边,然后删去所形成的环上面的最长边。
此题点数为 5000,对于每次交换,可以用树形DP求出所有点到 1 号点的最长边。每次选择增量最小的边去交换,直到 \(k_0\) 达到 L
在实现中的一些困难:
- 答案要求构成生成树的边序号,所以加边时要保留原边序号信息
- 树形DP要找到每个点到 根 的最长路大小,以及对应边的序号
- 如果一个点与根直接相连,可以把这个边序号保留下来(下面代码中用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 (单度限制最小生成树)的更多相关文章
- CodeForces 125E MST Company
E. MST Company time limit per test 8 seconds memory limit per test 256 megabytes input standard inpu ...
- CODEFORCES 125E MST Company 巧用Kruskal算法
题意:给定一个带权边无向图,求最小生成树,且满足第一个节点的度为固定的k 无解则输出-1 数据规模: 节点数n和限制k<=5000 边数m<=10^5 时限8sec 思路: 首先时限比较宽 ...
- 【CF125E】MST Company(凸优化,最小生成树)
[CF125E]MST Company(凸优化,最小生成树) 题面 洛谷 CF 题解 第一眼看见就给人丽洁姐那道\(tree\)一样的感觉. 那么二分一个权值,加给所有有一个端点是\(1\)的边, 然 ...
- luogu CF125E MST Company wqs二分 构造
LINK:CF125E MST Company 难点在于构造 前面说到了求最小值 可以二分出斜率k然后进行\(Kruskal\) 然后可以得到最小值.\(mx\)为值域. 得到最小值之后还有一个构造问 ...
- 【AtCoder3611】Tree MST(点分治,最小生成树)
[AtCoder3611]Tree MST(点分治,最小生成树) 题面 AtCoder 洛谷 给定一棵\(n\)个节点的树,现有有一张完全图,两点\(x,y\)之间的边长为\(w[x]+w[y]+di ...
- CF F. MST Unification (最小生成树避圈法)
题意 给一个无向加权联通图,没有重边和环.在这个图中可能存在多个最小生成树(MST),你可以进行以下操作:选择某条边使其权值加一,使得MST权值不变且唯一.求最少的操作次数. 分系:首先我们先要知道为 ...
- 度限制最小生成树 POJ 1639 贪心+DFS+prim
很好的解题报告: http://blog.csdn.net/new_c_yuer/article/details/6365689 注意两点: 1.预处理环中权值最大的边···· 2.可以把去掉度限制后 ...
- POJ 1679 The Unique MST (次小生成树 判断最小生成树是否唯一)
题目链接 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. De ...
- Solution -「CF 1025G」Company Acquisitions
\(\mathcal{Description}\) Link. \(n\) 个公司,每个公司可能独立或者附属于另一个公司.初始时,每个公司附属于 \(a_i\)(\(a_i=-1\) 表示该公 ...
随机推荐
- Python在项目外更改项目内引用
前言 目前有一个奇葩的需求, 将某个开源项目整合进自己的项目里去调度, 还需要在每次启动这个开源项目时, 加载不同的配置文件进去, 问题是配置文件并不是一个 conf 或者是其他的什么, 而是以 .p ...
- 【Java基础】面向对象中
面向对象中 这一章主要涉及面向对象的三大特征,包括封装.继承.多态.(抽象). 封装 程序设计追求"高内聚,低耦合": 高内聚 :类的内部数据操作细节自己完成,不允许外部干涉: 低 ...
- 【Flutter】事件处理与通知之原始指针事件处理
前言 接口描述 代码示例 总结
- 使用Jenkins+Pipline 持构建自动化部署之安卓源码打包、测试、邮件通知
一.引言 Jenkins 2.x的精髓是Pipeline as Code,那为什么要用Pipeline呢?jenkins1.0也能实现自动化构建,但Pipeline能够将以前project中的配置信息 ...
- docker 报错: Cannot connect to the Docker daemon at unix:///var/run/docker.sock.
最近在 Windows 子系统 WSL 上面安装了一个 ubuntu18.04, 安装完docker 跑 hello-world 的时候报错了 docker: Cannot connect to th ...
- 【Linux】iptables的内核模块问题大坑!
系统环境 CentOS 6.5 今天本来可以平静的度过一天,正品味着下午茶的美好,突然接到防火墙iptables的报警. 进入到服务器中,执行下面的命令查看,结果报错 /etc/init.d/ipta ...
- 【Linux】 多个会话同时执行命令后history记录不全的解决方案
基本认识 linux默认配置是当打开一个shell终端后,执行的所有命令均不会写入到~/.bash_history文件中,只有当前用户退出后才会写入,这期间发生的所有命令其它终端是感知不到的. 问题场 ...
- RabbitMQ六种工作模式有哪些?怎样用SpringBoot整合RabbitMQ
目录 一.RabbitMQ入门程序 二.Work queues 工作模式 三.Publish / Subscribe 发布/订阅模式 四.Routing 路由模式 五.Topics 六.Header ...
- 【源码解读】js原生消息提示插件
效果如下: 关闭message后前后message的衔接非常丝滑,这部分是我比较感兴趣的.带着这个问题先了解下DOM结构,顺便整理下作者的思路. 从DOM里我们可以看到所有的message都在一个容器 ...
- IPC图像处理项目流程图
网络摄像机IPC图像处理项目流程图: