zoukankan      html  css  js  c++  java
  • 【BZOJ3624】【APIO2008】免费道路 [生成树][贪心]

    免费道路

    Time Limit: 2 Sec  Memory Limit: 128 MB
    [Submit][Status][Discuss]

    Description

      

    Input

      

    Output

      

    Sample Input

      5 7 2
      1 3 0
      4 5 1
      3 2 0
      5 3 1
      4 3 0
      1 2 1
      4 2 1

    Sample Output

      3 2 0
      4 3 0
      5 3 1
      1 2 1

    HINT

      1<=n<=20000,1<=m<=100000,0<=k<=n-1

    Main idea

      一种0边,一种1边,求一棵最小生成树并且正好有K条0边,输出其中一种方案。

    Solution

      显然要搞一棵符合题目的生成树

      每次要加入0边或者1边,直接做肯定不可行,考虑有什么0边是一定要加入的。

      只需要输出一种方案,所以我们先加入所有可加的1边,如果图不联通则加入可加入的0边,那么这几条0边在我们所求的方案中是一定需要加入的。

      这时候判断一下,如果此时加入的0边数量>K,或者图还是无法联通的话则无解。然后处理完毕前半部分,考虑接下来如何实现。

      因为我们要使得图为树并且正好有K条0边,运用贪心,想到了加入0边到K条位置(如果到不了K条则也无解),然后剩下的用1边来填。

      验证一下这样做的可行性:由于我们在前半部分使得了可以成为一棵树,那么显然我们在后半部分中每加入一条0边,则在前半部分中一定有一条1边可以替换使得可行(因为前半部分是尽量加入1边)。每次连边判环运用Krusal即可。

    Code

      1 #include<iostream>  
      2 #include<algorithm>  
      3 #include<cstdio>  
      4 #include<cstring>  
      5 #include<cstdlib>  
      6 #include<cmath>  
      7 using namespace std;  
      8     
      9 const int ONE=1000001;
     10 const int INF=2147483640;
     11 
     12 int n,m,k;
     13 int Edge_k;
     14 int fa[ONE];
     15 int num;
     16 int Choose[ONE];
     17 int ans_num;
     18 int the0;
     19 
     20 struct power
     21 {
     22         int x,y,v;
     23 }a[ONE],Ans_edg[ONE];
     24 
     25 
     26 
     27 int get()
     28 { 
     29         int res,Q=1;    char c;
     30         while( (c=getchar())<48 || c>57)
     31         if(c=='-')Q=-1;
     32         if(Q) res=c-48; 
     33         while((c=getchar())>=48 && c<=57) 
     34         res=res*10+c-48; 
     35         return res*Q; 
     36 }
     37 
     38 int find(int x)
     39 {
     40         if(fa[x]!=x) fa[x]=find(fa[x]);
     41         return fa[x];
     42 }
     43 
     44 void Un(int a,int b)
     45 {
     46         int a1=find(a);
     47         int b1=find(b);
     48         if(a1!=b1) fa[a1]=b1;
     49 }
     50 
     51 int Add_set(int N,int v,int ci)
     52 {
     53         int kd=0;
     54         for(int i=1;i<=m;i++)
     55           {    
     56               if(kd>=N) break;
     57               
     58               if(a[i].v!=v) continue;
     59               
     60               int x=a[i].x,y=a[i].y;
     61               if(find(x)!=find(y))
     62               {
     63                   Un(x,y);
     64                   if(ci>=2)    Ans_edg[++ans_num]=a[i];
     65                   if(ci==2)
     66                   {
     67                       Choose[++num]=i;    
     68                 }
     69                 Edge_k++;
     70                 kd++;
     71                 if(ci==3) the0++;
     72             }
     73             if(Edge_k==n-1) break; 
     74         }
     75 }
     76 
     77 int main()
     78 {
     79           n=get();    m=get();    k=get();
     80           for(int i=1;i<=n;i++) fa[i]=i;
     81         for(int i=1;i<=m;i++)
     82         {
     83             a[i].x=get();    a[i].y=get();    a[i].v=get();
     84         }
     85           Edge_k=0;
     86               
     87           Add_set(INF,1,1);
     88           Add_set(INF,0,2);
     89           
     90           if(Edge_k<n-1 || num>k)
     91           {
     92               printf("no solution
    ");
     93               return 0;
     94         }
     95           
     96           Edge_k=0;
     97           for(int i=1;i<=n;i++) fa[i]=i;
     98           for(int i=1;i<=num;i++)
     99           {
    100               int x=Choose[i];
    101               Un(a[x].x,a[x].y);
    102             Edge_k++;
    103             if(Edge_k==n-1) break;
    104         }
    105           
    106           Add_set(k-num,0,3);
    107         if(the0!=k-num)
    108           {
    109               printf("no solution
    ");
    110             return 0;    
    111         }
    112         
    113           Add_set(INF,1,4);
    114           for(int i=1;i<=ans_num;i++)
    115           {
    116               printf("%d %d %d
    ",Ans_edg[i].x,Ans_edg[i].y,Ans_edg[i].v);
    117         }
    118           
    119 }
    View Code
  • 相关阅读:
    在MS Sql Server中可以能过以下的方法查询出磁盘空间的使用情况及各数据库数据文件及日志文件的大小及使用利用率:
    sqlserver日志的备份与还原
    C#中String 与Color之间的相互转换
    sql 替换字符串
    Components_Box
    射线检测与碰撞通道设置
    切碎方块
    音乐可视化
    枚举
    UI与Actor(蓝图)的互动
  • 原文地址:https://www.cnblogs.com/BearChild/p/6430006.html
Copyright © 2011-2022 走看看