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\) 表示该公 ...
随机推荐
- 【Azure Redis 缓存】Azure Redis功能性讨论
关于使用Azure Redis服务在以下九大方面的功能性的解说: 高可用 备份可靠性 配置自动化 部署多样性 快速回档功能 数据扩容 SLA稳定性 数据安全性 监控系统 一:高可用 Azure Cac ...
- 发现一个怪象windows 7系统上老是丢包windows 10网络正常
不知何故障,同一个局域网,windows 10系统上不丢包,windows 7系统老是丢包,不知是不是这二个系统的差区别,还是大家都有这样的情况. 相互PC之间ping也又不丢包,只有windos 7 ...
- 爬虫-urllib模块的使用
urllib是Python中请求url连接的官方标准库,在Python3中将Python2中的urllib和urllib2整合成了urllib.urllib中一共有四个模块,分别如下: request ...
- 【Flutter】功能型组件之导航返回拦截
前言 为了避免用户误触返回按钮而导致APP退出,在很多APP中都拦截了用户点击返回键的按钮,然后进行一些防误触判断,比如当用户在某一个时间段内点击两次时,才会认为用户是要退出(而非误触).Flutte ...
- LeetCode222 判断是否为完全二叉树并求节点个数
给出一个完全二叉树,求出该树的节点个数. 说明: 完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置.若最底 ...
- 编译安装 nginx -1.14.2
编译安装 nginx -1.14.2 1 ) 下载nginx-1.14.2 源码包: wget http://nginx.org/download/nginx-1.14.2.tar.gz 2 ) 编译 ...
- git文件操作
git下载地址: https://git-scm.com/download mac 直接使用brew下载brew install git 1Git一般工作流程: 1.在工作目录创建版本库 2.在工作目 ...
- 你都用过SpringCloud的哪些组件,它们的原理是什么?
前言 看到文章的题目了吗?就是这么抽象和笼统的一个问题,确实是我面试中真实被问到的,某共享货车平台的真实面试问题. SpringCloud确实是用过,但是那是三四年前了,那个时候SpringCloud ...
- 怎么判断innodb 日志缓冲区该设置为多大呢
怎么判断innodb 日志缓冲区该设置为多大呢
- Java反射全解析(使用、原理、问题、在Android中的应用)
前言 今天说Java模块内容:反射. 反射介绍 正常情况下,我们知晓我们要操作的类和对象是什么,可以直接操作这些对象中的变量和方法,比如一个User类: User user=new User(); u ...