题目:

  点这里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. PAT A1009 Product of Polynomials(25)

    课本AC代码 #include <cstdio> struct Poly { int exp;//指数 double cof; } poly[1001];//第一个多项式 double a ...

  2. 【动态规划】Mathematical Curse

    [来源]:2018年焦作网络赛B [题意]: 有n个数字,有m个符号运算.通过不回头(即选取m个数有顺序可言),消除巫术的,并达到最大的价值. 其实意思就是在数组里选取一段子序列,然后进行m次加减乘除 ...

  3. CentOS7-部署kubernetes

    1 环境准备   节点 主机名 IP OS Master     k8s-master        192.168.57.1       centos 7        Node1  k8s-nod ...

  4. python函数篇0-1

    创建类和对象 面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用. 类就是一个模板,模板里可以包含多个函数, ...

  5. docker CMD 和 ENTRYPOINT 区别

    昨天用Dockerfile来启动mongodb的集群,启动参数--replSet死活没执行,最后就决定研究一哈cmd和entrypoint.但是上网看了一些资料个人觉得讲的不好,还是没有说出根本的东西 ...

  6. 怎样使用 v-bind 绑定 html 标签的属性值?

    1. 在 Vue 中可是使用 v-bind 对 html 中的 属性 进行绑定, 如下所示, 我们想给这个 a 标签绑定一个 title 值: <!DOCTYPE html> <ht ...

  7. Java多线程(二):Thread类

    Thread类的实例方法 start() start方法内部会调用方法start方法启动一个线程,该线程返回start方法,同时Java虚拟机调用native start0启动另一个线程调用run方法 ...

  8. 转:git上传本地项目到github

    转自:https://blog.csdn.net/Lucky_LXG/article/details/77849212 将本地项目上传到Github(两种简单.方便的方法) 一.第一种方法:首先你需要 ...

  9. react——使用this.setState({ })修改state状态值

    使用this.setState({  }) 还可以修改后追加传的参数 效果如下: this.setState({  })方法是异步的

  10. GitLab 部署及管理员账号初始化

    Linux系统搭建GitLab---阿里云Centos7搭建Gitlab踩坑一.简介GitLab,是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git项目仓库,可通过We ...