CODEFORCES 125E MST Company 巧用Kruskal算法
题意:给定一个带权边无向图,求最小生成树,且满足第一个节点的度为固定的k 无解则输出-1
数据规模: 节点数n和限制k<=5000 边数m<=10^5 时限8sec
思路:
首先时限比较宽,第一个想到的暴力做法是枚举第一个节点(即首都)选中的K条边,复杂度为阶乘级别 无法接受。但是我们可以确定,问题的关键在于在所有国道中选择哪k条国道。一旦k条国道选定,最小生成树就是固定的。
考虑一个极端的情况,如果我们直接对这个图运行Kruskal算法,得到了一个树 且 第一个节点的度为k,则这就是正确的答案。当然,一般数据是无法做到的。
那么我们就可以使用一个技巧,如果运行Kruskal算法后第一个节点的度小于k,那么我们在算法运行的序列中将所有国道的位置整体向前移动,使得下一次运行Kruskal算法可以选定更多的国道,我们就离正确答案更近了。反之亦然。
那么怎样调整所有“国道”在Kruskal序列中的位置呢?
选定一个double值mid 它可以很大,也可以很小,在排序时“国道”的权值加上这个mid再与非国道比较,就可以适当的调节所有“国道”在序列中的位置。
代码如下,只要理解了排序比较函数cmp 也就理解了这个Kruskal的变种算法了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<algorithm>
using namespace std;
const int maxn=+,maxm=+;
int x[maxm],y[maxm],w[maxm],sig[maxm],ance[maxn],ans[maxn];
int n,m,k,tot,cnt,captedge;
double l,r,mid;
bool cmp(int a,int b)
{
return (w[a]+(x[a]==)*mid)<(w[b]+(x[b]==)*mid);//这个算法的核心
}
int findance(int x)
{
if(x==ance[x])return x;
else return ance[x]=findance(ance[x]);
}
void Kruskal(bool flag)
{
cnt=captedge=;
for(int i=;i<=n;i++)
{
ance[i]=i;
}
sort(sig,sig+m,cmp);
for(int i=;i<m;i++)
{
if(cnt+==n) return ;
int j=sig[i];
int u=findance(x[j]),v=findance(y[j]);
if((u!=v)&&(flag||(captedge+(x[j]==))<=k)) {
ance[u]=v;
ans[cnt++]=j;
if(x[j]==)captedge++;
}
}
}
int main()
{
ios::sync_with_stdio(false);
freopen("t.txt","r",stdin);
cin>>n>>m>>k;
tot=;
for(int i=;i<m;i++)
{
sig[i]=i;
cin>>x[i]>>y[i]>>w[i];
if(x[i]>y[i]){int t=x[i];x[i]=y[i];y[i]=t;}//swap
if(x[i]==)tot++;
}
if((k>tot)||(k==&&n>))
{
cout<<"-1"<<endl;
return ;
}
cnt=;
Kruskal();
if(cnt!=(n-))
{
cout<<"-1"<<endl;
return ;
}
l=(-)*100000.0;
r=100000.0;
while(((l+1e-)<r)&&(captedge!=k))
{
mid=(l+r)/2.0;
Kruskal();
if(captedge<k)r=mid;
else l=mid;
}
if(captedge!=k)mid=(l+r)/2.0;
Kruskal();
cout<<n-<<endl;
if(cnt>=)cout<<ans[]+;
for(int i=;i<cnt;i++)
cout<<" "<<ans[i]+;
cout<<endl;
return ;
}
CODEFORCES 125E MST Company 巧用Kruskal算法的更多相关文章
- CodeForces 125E MST Company
E. MST Company time limit per test 8 seconds memory limit per test 256 megabytes input standard inpu ...
- POJ 1679 The Unique MST (次小生成树kruskal算法)
The Unique MST 时间限制: 10 Sec 内存限制: 128 MB提交: 25 解决: 10[提交][状态][讨论版] 题目描述 Given a connected undirect ...
- MST最小生成树及克鲁斯卡尔(Kruskal)算法
最小生成树MST,英文名如何拼写已忘,应该是min spaning tree吧.假设一个无向连通图有n个节点,那么它的生成树就是包括这n个节点的无环连通图,无环即形成树.最小生成树是对边上权重的考虑, ...
- HDU 2682 Tree(Kruskal算法求解MST)
题目: There are N (2<=N<=600) cities,each has a value of happiness,we consider two cities A and ...
- HDU 5253 连接的管道(Kruskal算法求解MST)
题目: 老 Jack 有一片农田,以往几年都是靠天吃饭的.但是今年老天格外的不开眼,大旱.所以老 Jack 决定用管道将他的所有相邻的农田全部都串联起来,这样他就可以从远处引水过来进行灌溉了.当老 J ...
- ZOJ 1586 QS Network(Kruskal算法求解MST)
题目: In the planet w-503 of galaxy cgb, there is a kind of intelligent creature named QS. QScommunica ...
- POJ 1251 Jungle Roads(Kruskal算法求解MST)
题目: The Head Elder of the tropical island of Lagrishan has a problem. A burst of foreign aid money w ...
- 最小生成树(MST)Prim算法和Kruskal算法
刚学完最小生成树,赶紧写写学习的心得(其实是怕我自己忘了) 最小生成树概念:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边. 就是说 ...
- 图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用
图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 ...
随机推荐
- POJ 2395 Out of Hay
这个问题等价于求最小生成树中权值最大的边. #include<cstdio> #include<cstring> #include<cmath> #include& ...
- Web开发中需要了解的东西
在StackExchange上有人问了这样一个问题:What should every programmer know about web development?(关于Web开发,什么是所有程序员需 ...
- FZU 1056 扫雷游戏
水题.统计一下周围有几个雷. #include<cstdio> #include<cstring> #include<cmath> #include<algo ...
- Android L(5.0)源码之图形与图像处理之图形特效——Matrix
最近在研究android 5.0的gallery模块,学习了相关的知识点,准备写点博客总结一下,有时间了会补充完整
- 用weka来做Logistic Regression
1.首先下载安装weka http://www.cs.waikato.ac.nz/ml/weka/downloading.html 2.打开weka,选择第一项Explorer 3.准备数据集文件,在 ...
- easyui-01 怎么样使用easyui
console.info();在控制台打印. 1.引入 <script type="text/javascript" src="../../jquery-easyu ...
- 解决tomcat运行报错java.lang.UnsatisfiedLinkError: apache-tomcat-7.0.37\bin\tcnative-1.dll:Can load AMD 64
http://www.apache.org/dist/tomcat/tomcat-connectors/native/ 到该地址下下载一个tomcat-native-1.2.2-win32-bin压缩 ...
- 360路由器设置网段ip
路由器设置->高级设置->修改路由器地址
- 查看Linux最近重启的时间
最近实验室老是掉电,想查看服务器什么时候重启的,于是在网上找了一些资料.有两种方式可以查看服务器重启. (1) who -b (2) last reboot |head -1
- Treap初步
模板题 bzoj3224: Tyvj 1728 普通平衡树 #include <bits/stdc++.h> #define rep(i, a, b) for (int i = a; i ...