题目:

  点这里OvO http://acm.hdu.edu.cn/showproblem.php?pid=6041

  2017 Multi-University Training Contest - Team 1 - 1009    

题解:

  1.由于每条边只在一个环中,每个环必然要拿掉一条边,而这些边都是不重复的,那么最小生成树就对应的是通过求每个环中拿掉一条边,总和最大的组合对应的剩下的树(第k小生成树对应第k大组合剩下的树)。xjbdfs搜一下环,把每个环中的点放到一个集合中。

  2.然后对集合排序,xjb利用优先队列 ( 要注意优先队列中的元素的数量要保持和新集合的元素个数相同,以降低时间复杂度 ) 求最大的k(如果总数没k个那就不是k个)个组合(每个集合中取一个元素的组合)

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue> using namespace std; typedef long long ll; const int N=1e4+;
const int M=2e3+;
const ll mod=(ll)pow(,); struct node{
int u,v,d;
int next;
}edge[*N]; struct NODE
{
int v,now; //value is (v), now add with (now)
friend bool operator<(NODE x,NODE y)
{
return x.v < y.v;
}
};//small to big priority_queue<NODE> Q;
int num;
int head[N];
int n,m,k;
ll ans;
int snum;
int stk[N],lstk;
bool instk[M];
vector<int> s[N];
int val[M][M];
vector<int> f,tmpf;
ll sum_of_edge;
ll du[M]; bool cmp(int a,int b)
{
return a>b;
} void addedge(int u,int v,int d)
{
edge[num].u=u;
edge[num].v=v;
edge[num].d=d;
edge[num].next=head[u];
head[u]=num++;
} void init()
{
num=; //记得初始化
memset (head,-,sizeof(head));
memset(du,,sizeof(du));
snum=;
lstk=;
memset(instk,,(n+)*sizeof(bool));
for(int i=;i<=n;i++)
s[i].clear();
ans=;
sum_of_edge=;
} void dfs(int rt,int fa)
{
int v;
if(instk[rt])
{
snum++;
int sav=rt;
int sav_lstk=lstk;
while(stk[lstk]!=rt)
{
s[snum].push_back(val[sav][stk[lstk]]);
sav=stk[lstk--];
}
s[snum].push_back(val[sav][stk[lstk]]);
lstk=sav_lstk;
return ;
}
instk[rt]=;
stk[++lstk]=rt;
for(int i=head[rt];i!=-;i=edge[i].next)
{
v=edge[i].v;
if(v==fa || du[v]==) continue;
du[rt]--; du[v]--;
dfs(v,rt);
}
instk[rt]=;
lstk--;
} void merge()
{
NODE q;
int i,j,cnt;
f.clear();
if(snum==)
{
f.push_back();
return ;
}
for(int i=;i<s[].size();i++)
f.push_back(s[][i]);
for(int i=;i<=snum;i++)
{
cnt=f.size()*s[i].size();
if(cnt>k) cnt=k;
while(!Q.empty())
Q.pop();
for(j=;j<s[i].size();j++)
{
q.v=s[i][j]+f[];
q.now=;
Q.push(q);
}
tmpf.clear();
while(cnt--)
{
q=Q.top();
Q.pop();
tmpf.push_back(q.v);
if(q.now!=f.size()-)
{
q.v-=f[q.now];
q.now++;
q.v+=f[q.now];
Q.push(q);
}
}
swap(f,tmpf);
}
// cout<<"check merge\n";
// for(int i=0;i<f.size();i++)
// printf("%d ",f[i]);
// printf("\n");
// printf("end of check of merge\n");
} void solve()
{
dfs(,-);
for(int i=;i<=snum;i++)
sort(s[i].begin(),s[i].end(),cmp);
// printf("check s\n");
// for(int i=1;i<=snum;i++)
// {
// for(int j=0;j<s[i].size();j++)
// printf("%d",s[i][j]);
// printf("\n");
// }
// printf("end of check of s\n");
merge();
} int main()
{
int cas=,a,b,c;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
du[a]++; du[b]++;
val[a][b]=val[b][a]=c;
sum_of_edge+=c;
}
scanf("%d",&k);
solve();
for(int i=;i<f.size();i++)
ans=(ans+1ll*(i+)*(sum_of_edge-f[i])%mod)%mod;
printf("Case #%d: %lld\n",++cas,ans%mod);
}
return ;
}

hdu 6041 I Curse Myself的更多相关文章

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

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

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

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

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

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

  4. hdu 6041 I Curse Myself 无向图找环+优先队列

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

  5. HDU 6041 I Curse Myself(点双联通加集合合并求前K大) 2017多校第一场

    题意: 给出一个仙人掌图,然后求他的前K小生成树. 思路: 先给出官方题解 由于图是一个仙人掌,所以显然对于图上的每一个环都需要从环上取出一条边删掉.所以问题就变为有 M 个集合,每个集合里面都有一堆 ...

  6. HDU 6041 I Curse Myself ——(仙人掌图,tarjan,转化)

    题解见这个博客:http://blog.csdn.net/ME495/article/details/76165039. 复杂度不太会算..这个经典问题的解法需要注意,维护队列里面只有k个元素即可.另 ...

  7. HDU - 6041:I Curse Myself(Tarjan求环&K路归并)

    There is a connected undirected graph with weights on its edges. It is guaranteed that each edge app ...

  8. HDU 2520 我是菜鸟,我怕谁

    我是菜鸟,我怕谁 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  9. HDU 5433 Xiao Ming climbing 动态规划

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5433 Xiao Ming climbing Time Limit: 2000/1000 MS (Ja ...

随机推荐

  1. 【转帖】Linux图形用户界面:KDE与GNOME的由来

    Linux图形用户界面:KDE与GNOME的由来 置顶 2018年08月11日 15:51:25 hwpipixia 阅读数 4778 https://blog.csdn.net/u013895853 ...

  2. Spring 循环依赖的三种方式(三级缓存解决Set循环依赖问题)

    本篇文章解决以下问题: [1] . Spring循环依赖指的是什么? [2] . Spring能解决哪种情况的循环依赖?不能解决哪种情况? [3] . Spring能解决的循环依赖原理(三级缓存) 一 ...

  3. SpringBoot起飞系列-拦截器和统一错误处理(七)

    一.前言 在前边部分我们已经学会了基本的web开发流程,在web开发中,我们通常会对请求做统一处理,比如未登录的用户要拦截掉相关请求,报错页面统一显示等等,这些都需要配置,可以大大简化我们的代码,实现 ...

  4. Educational Codeforces Round 68 (Rated for Div. 2)补题

    A. Remove a Progression 签到题,易知删去的为奇数,剩下的是正偶数数列. #include<iostream> using namespace std; int T; ...

  5. 使用rpm安装mysql 5.7和依赖们

    在安装mysql-server之前,需要安装相应的依赖,当前系统环境是CentOS7,需要安装3个依赖,mysql-community-common,mysql-community-libs,mysq ...

  6. winform中如何在多线程中更新UI控件--ListView实时显示执行信息

    1.在winform中,所有对UI的操作,都得回到UI线程(主线程)上来,才不会报错 线程间操作无效: 从不是创建控件的线程访问它. 2.在winform中,允许通过Control.invoke对控件 ...

  7. java:线上问题排查常用手段(转)

    出处:java:线上问题排查常用手段 一.jmap找出占用内存较大的实例 先给个示例代码: import java.util.ArrayList; import java.util.List; imp ...

  8. 关于KMP中求next数组的思考【转】

    文章转自 http://www.tuicool.com/articles/yayeIbe.这是我看到关于求next数组,解释最好的一篇文章!!!!!!! KMP的next数组求法是很不容易搞清楚的一部 ...

  9. 修改mac系统的host文件 (一)

    hosts是本地预先配置的DNS数据,解析域名的时候首先试图从hosts文件获取,没有则从DNS服务器获取. 此文件的三个主要用途: 加快域名解析 方便局域网用户 一般局域网很少假设DNS服务器,访问 ...

  10. C#委托的定义 以及使用方式详解,更简单的理解委托。

    委托的声明及定义: 委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得 ...