zoukankan      html  css  js  c++  java
  • 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的变种算法了。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<queue>
     6 #include<stack>
     7 #include<map>
     8 #include<algorithm>
     9 using namespace std;
    10 const int maxn=5000+1,maxm=100000+1;
    11 int x[maxm],y[maxm],w[maxm],sig[maxm],ance[maxn],ans[maxn];
    12 int n,m,k,tot,cnt,captedge;
    13 double l,r,mid;
    14 bool cmp(int a,int b)
    15 {
    16  return (w[a]+(x[a]==1)*mid)<(w[b]+(x[b]==1)*mid);//这个算法的核心 
    17 }
    18 int findance(int x)
    19 {
    20  if(x==ance[x])return x;
    21      else return ance[x]=findance(ance[x]);
    22 }
    23 void Kruskal(bool flag)
    24 {
    25  cnt=captedge=0;
    26  for(int i=1;i<=n;i++)
    27      {
    28       ance[i]=i;
    29     }
    30  sort(sig,sig+m,cmp);
    31  for(int i=0;i<m;i++)
    32      {
    33       if(cnt+1==n)    return ;
    34       int j=sig[i];
    35       int u=findance(x[j]),v=findance(y[j]);
    36       if((u!=v)&&(flag||(captedge+(x[j]==1))<=k))
    37           
    38         {
    39          ance[u]=v;
    40          ans[cnt++]=j;
    41          if(x[j]==1)captedge++;
    42         }
    43     }
    44 }
    45 int main()
    46 {
    47  ios::sync_with_stdio(false);
    48  freopen("t.txt","r",stdin);
    49  cin>>n>>m>>k;
    50  tot=0;
    51  for(int i=0;i<m;i++)
    52      {
    53       sig[i]=i;
    54      cin>>x[i]>>y[i]>>w[i];
    55      if(x[i]>y[i]){int t=x[i];x[i]=y[i];y[i]=t;}//swap     
    56      if(x[i]==1)tot++;
    57     }
    58  if((k>tot)||(k==0&&n>1))
    59      {
    60       cout<<"-1"<<endl;
    61      return 0;    
    62     }
    63  cnt=0;
    64  Kruskal(1);
    65  if(cnt!=(n-1))
    66      {
    67       cout<<"-1"<<endl;
    68      return 0;    
    69     }
    70  l=(-1)*100000.0;
    71  r=100000.0;
    72  while(((l+1e-5)<r)&&(captedge!=k))
    73      {
    74       mid=(l+r)/2.0;
    75       Kruskal(1);
    76       if(captedge<k)r=mid;
    77           else l=mid;
    78     }
    79  if(captedge!=k)mid=(l+r)/2.0;
    80  Kruskal(0);
    81  cout<<n-1<<endl;
    82  if(cnt>=1)cout<<ans[0]+1;
    83  for(int i=1;i<cnt;i++)
    84      cout<<" "<<ans[i]+1;
    85  cout<<endl;
    86  return 0;
    87 }
  • 相关阅读:
    nginx 自启动脚本
    debian开机启动管理
    vagrant up connection time out
    vagrant在windows下的使用
    Office Web Apps Server
    邻接表模型中的节点移动
    Managing Hierarchical Data in MySQL(邻接表模型)[转载]
    play mp3 in c#
    2014年5月份第3周51Aspx源码发布详情
    2014年5月份第2周51Aspx源码发布详情
  • 原文地址:https://www.cnblogs.com/heisenberg-/p/6341406.html
Copyright © 2011-2022 走看看