【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\n");
 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\n");
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\n",Ans_edg[i].x,Ans_edg[i].y,Ans_edg[i].v);
117         }
118           
119 }
View Code

 

posted @ 2017-02-22 17:29  BearChild  阅读(230)  评论(0编辑  收藏  举报