题意:

给出一个仙人掌图,然后求他的前K小生成树。

思路:

先给出官方题解

由于图是一个仙人掌,所以显然对于图上的每一个环都需要从环上取出一条边删掉。所以问题就变
为有 M 个集合,每个集合里面都有一堆数字,要从每个集合中选择一个恰好一个数加起
来。求所有的这样的和中,前 K 大的是哪些。这就是一个经典问题了。

点双联通就不说了 都一眼能看出来做法就是缩点之后每个环每次取一个,然后找最大的k个所以这道题的难点就在这里,做法当然是不知道啦,看了题解和博客才懂的。以前做过两个集合合并的,这个是k个合并,和两个集合合并差不多,不过感觉很厉害啊。。就是先两个合并,然后和第三个合并,在和第四个,然后就可以了。。复杂度的话题解说的O(KM)。。。那就O(KM)吧,反正这个是真不会证过程挺厉害的 在合并的时候

void merge(vector<int> &V , vector<int> B) {
priority_queue< opt > Q;
for (int i = 0 ; i < B.size() ; ++ i) {
Q.push((opt) {V[0] + B[i] , i , 0});
}
W.resize(0);
while (W.size() < K && !Q.empty()) {
auto it = Q.top(); Q.pop();
W.push_back(it.w);
if (it.y + 1 < V.size()) {
++ it.y;
Q.push((opt) {B[it.x] + V[it.y] , it.x , it.y});
}
}
V = W;
}

最开始一直没看懂  看了一天呀。。。  后来想通了感觉还是挺简单的,然后在本机跑,没开O2跑了大半辈子。。。

具体过程其实就是对于每个已经合并了的数组,最开始让他最大的和B数组合并,然后对于已经合并了的数组,如果当前

的这一位被push进答案数组,那么就把先合并数组的次大的和B数组的当前数字合并就可以了。

思路挺厉害的~

代码就贴标程的吧~

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n , m , K; struct opt {
int w , x , y;
bool operator < (const opt& R) const {
return w < R.w;
}
}; vector<int> W;
void merge(vector<int> &V , vector<int> B) {
priority_queue< opt > Q;
for (int i = 0 ; i < B.size() ; ++ i) {
Q.push((opt) {V[0] + B[i] , i , 0});
}
W.resize(0);
while (W.size() < K && !Q.empty()) {
auto it = Q.top(); Q.pop();
W.push_back(it.w);
if (it.y + 1 < V.size()) {
++ it.y;
Q.push((opt) {B[it.x] + V[it.y] , it.x , it.y});
}
}
V = W;
} int pre[N] , mcnt;
struct edge {
int x , w , next;
} e[N << 2]; vector<int> res; int dfn[N] , low[N] , ncnt;
stack<int> S; void dfs(int x , int fa) {
dfn[x] = low[x] = ++ ncnt;
for (int i = pre[x] ; ~i ; i = e[i].next) {
int y = e[i].x;
if (!dfn[y]) {
S.push(i);
dfs(y , i ^ 1);
low[x] = min(low[x] , low[y]);
if (low[y] > dfn[x]) {}//(x , y) is bridge
if (low[y] >= dfn[x]) {
int j;
vector<int> V;
do {
j = S.top();
S.pop();
V.push_back(e[j].w);
} while (j != i);
if (V.size() > 1) {
//cout << V.size() << endl;
//for (auto &x : V) cout << x << ' '; cout << endl;
merge(res , V);
}
}
} else if (i != fa && dfn[y] < dfn[x])
S.push(i) , low[x] = min(low[x] , dfn[y]);
}
} void work() {
memset(pre , -1 , sizeof(pre));
mcnt = ncnt = 0;
int sum = 0;
for (int i = 0 ; i < m ; ++ i) {
int x , y , z;
scanf("%d%d%d" , &x , &y , &z);
e[mcnt] = (edge) {y , z , pre[x]} , pre[x] = mcnt ++;
e[mcnt] = (edge) {x , z , pre[y]} , pre[y] = mcnt ++;
sum += z;
}
scanf("%d" , &K);
res.resize(0);
res.push_back(0);
memset(dfn , 0 , sizeof(dfn));
dfs(1 , 0);
int w = 0;
for (int i = 0 ; i < res.size() ; ++ i) {
w += (i + 1) * (sum - res[i]);
}
static int ca = 0;
printf("Case #%d: %u\n" , ++ ca , w);
} int main() {
res.reserve(100001);
W.reserve(100001);
while (~scanf("%d%d" , &n , &m)) {
work();
}
return 0;
}

HDU 6041 I Curse Myself(点双联通加集合合并求前K大) 2017多校第一场的更多相关文章

  1. hdu 6044 : Limited Permutation (2017 多校第一场 1012) 【输入挂 组合数学】

    题目链接 参考博客: http://blog.csdn.net/jinglinxiao/article/details/76165353 http://blog.csdn.net/qq_3175920 ...

  2. hdu 6035:Colorful Tree (2017 多校第一场 1003) 【树形dp】

    题目链接 单独考虑每一种颜色,答案就是对于每种颜色至少经过一次这种的路径条数之和.反过来思考只需要求有多少条路径没有经过这种颜色即可. 具体实现过程比较复杂,很神奇的一个树形dp,下面给出一个含较详细 ...

  3. HDU 6041.I Curse Myself 无向仙人掌图

    I Curse Myself Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) ...

  4. HDU 6041 - I Curse Myself | 2017 Multi-University Training Contest 1

    和题解大致相同的思路 /* HDU 6041 - I Curse Myself [ 图论,找环,最大k和 ] | 2017 Multi-University Training Contest 1 题意 ...

  5. HDU 2639 01背包求第k大

    Bone Collector II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  6. HDU 6041 I Curse Myself(二分+搜索)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6041 [题目大意] 给出一个仙人掌图,求第k小生成树 [题解] 首先找到仙人掌图上的环,现在的问题 ...

  7. hdu 6041 I Curse Myself

    题目: 点这里OvO http://acm.hdu.edu.cn/showproblem.php?pid=6041 2017 Multi-University Training Contest - T ...

  8. lightoj 1300 边双联通分量+交叉染色求奇圈

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1300 边双连通分量首先dfs找出桥并标记,然后dfs交叉着色找奇圈上的点.这题只要求在 ...

  9. poj 3177&&3352 求边双联通分量,先求桥,然后求分量( 临界表代码)

    /*这道题是没有重边的,求加几条边构成双联通,求边联通分量,先求出桥然后缩点,成一个棵树 找叶子节点的个数*/ #include<stdio.h>//用容器写在3177这个题上会超内存,但 ...

随机推荐

  1. HTML学习笔记(一)HTML的一些概念区别

    HTML HTML 指超文本标记语言.在 HTML 4 中,有若干的标签和属性是被废弃的,替换成style对应的属性 应该避免使用下面这些标签和属性: 标签 描述 style <center&g ...

  2. 01 | VIM基础攻略

    启动 vim 后,vim 处于 normal 模式. Step One: "i" -> insert 模式, ESC -> normal 模式: "x&quo ...

  3. 推荐一款功能齐全的开源客户端( iOS 、Android )研发助手。

    DoraemonKit ,简称DoKit,中文名 哆啦A梦,意味着能够像哆啦A梦一样提供给他的主人各种各样的工具. 开发背景 每一个稍微有点规模的 App,总会自带一些线下的测试功能代码,比如环境切换 ...

  4. PAT甲级——1135 Is It A Red-Black Tree (30 分)

    我先在CSDN上面发表了同样的文章,见https://blog.csdn.net/weixin_44385565/article/details/88863693 排版比博客园要好一些.. 1135 ...

  5. B.选点

    链接:https://ac.nowcoder.com/acm/contest/368/B 题意: 有一棵n个节点的二叉树,1为根节点,每个节点有一个值wi.现在要选出尽量多的点. 对于任意一棵子树,都 ...

  6. Hive_Hive体系结构

     元数据: HQL的执行过程 ORACEL 执行计划,Hive 类似. 无索引时,生成全表扫描执行计划,执行全表扫描.  创建索引后,重新生成SQL语句执行计划,基于索引扫描,提高查询效率.

  7. SpringMVC-异常处理器

    1.    异常处理思路 系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发.测试通过手段减少运行时异常的发生. 系统 ...

  8. c#学习系列之字段(静态,常量,只读)

    C#静态变量使用 static 修饰符进行声明,在类被实例化时创建,通过类进行访问不带有 static 修饰符声明的变量称做非静态变量.static变量在对象被实例化时创建,通过对象进行访问一个类的所 ...

  9. 使用express+mongoDB搭建多人博客 学习(6)发表文章

    发表文章 1.在modules文件夹下新建post.js var mongodb=require("./db"); function Post(name,title,post){ ...

  10. Redis特点

    内存存储,速度极快. 支持的数据类型多,相比较其他的Nosql. 键:字符串 值的六种数据结构:字符串,列表,散列,集合,有序集合,HyperLogLog 附加功能强大