1. 程式人生 > >Bzoj 3624: [Apio2008]免費道路 (貪心+生成樹)

Bzoj 3624: [Apio2008]免費道路 (貪心+生成樹)

道路 並查集 -1 struct clas content http class api

技術分享

技術分享

技術分享

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
  這道題當時光讀題就讀半天,現在大概翻譯一下:     我們需要對於該圖建一棵生成樹使所有點連通,並且這棵樹裏有且只有K條白邊。    讀明白後就想到了[國家集訓隊2012]tree(陳立傑),那道題也是類似,要求白邊數量恰好為need,但是那道題要求是最小生成樹,而這道題只要是生成樹就好了。而且還得判斷和不合法。然後就開始想,假設我們先扣掉所有白邊,那麽剩下的就是由黑邊組成的一個個聯通塊了。然後呢?就不知道了,一開始想去用並查集搞,但是沒搞出什麽名堂,也就放棄了。
  正解的確還是最小生成樹,額,或許不應該說是最小生成樹,但是的確要用克魯斯卡爾,我們先把黑邊優先,這樣,我們就可以先找出造出一個生成樹的下限,如果k比他還小那麽顯然不行。同理,我們再白邊優先,找出生成樹的上限,如果k比他大那麽仍然不行。   合法性我們解決完了,答案怎麽出來呢?   讓我們先回顧樹的一個性質:當我們在一棵樹上,從一個點向另一個點連邊時樹就會被破壞,但是,當我們拆開由這兩個邊組成的環上的任意一點時,樹又變得合法。   首先,對於我們找出白邊下限時找出的白邊我們都是無法找出黑邊將他們替換的,說白了,我們必須選上他們。   其次,對於剩下的白邊,我們可以意識到,我們之所以沒有把它們在找下限時把它找到是因為它可以被一個黑邊或者白邊代替,如果它被白邊代替,那麽我們仍然不必選他,因為那條白邊是一定要選的,當然,我們可以把它和那條白邊替換,但既然是spj,這有什麽意義呢?
   如果他是被黑邊替換,那麽我們如果先選他也就不必再去選那條黑邊,因此,我們先把必須選白邊選上,再貪心去找那些被黑邊替換的白邊,找夠了就只去找黑邊,最終輸出答案就好了。 技術分享
  1 #include <iostream>
  2 #include <cstdlib>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <queue>
  6 #include <algorithm>
  7 #include <cmath>
  8 #include <map>
  9
#define N 20005 10 #define M 100005 11 using namespace std; 12 int n,m,t,fa[N]; 13 struct ro 14 { 15 int to,from,l; 16 bool bj; 17 }road[M]; 18 bool px1(ro a,ro b) 19 { 20 return a.l>b.l; 21 } 22 bool px2(ro a,ro b) 23 { 24 return a.l<b.l; 25 } 26 int find(int x) 27 { 28 if(fa[x]==x)return x; 29 return fa[x]=find(fa[x]); 30 } 31 void hb(int x,int y) 32 { 33 int a=find(x),b=find(y); 34 fa[a]=b; 35 } 36 int ans[N]; 37 int main() 38 { 39 scanf("%d%d%d",&n,&m,&t); 40 int sum=0; 41 for(int i=1;i<=n;i++)fa[i]=i; 42 for(int i=1;i<=m;i++) 43 { 44 scanf("%d%d%d",&road[i].from,&road[i].to,&road[i].l); 45 if(!road[i].l)sum++; 46 } 47 sort(road+1,road+1+m,px1); 48 int js1=0,js2=0; 49 for(int i=1;i<=m;i++) 50 { 51 int x=road[i].from,y=road[i].to; 52 if(find(x)!=find(y)) 53 { 54 js1++; 55 if(!road[i].l) 56 { 57 road[i].bj=1; 58 js2++; 59 } 60 hb(x,y); 61 } 62 if(js1==n-1)break; 63 } 64 if(js1!=n-1||js2>t) 65 { 66 printf("no solution\n"); 67 exit(0); 68 } 69 sort(road+1,road+1+m,px2); 70 js1=0,js2=0; 71 for(int i=1;i<=n;i++)fa[i]=i; 72 for(int i=1;i<=sum;i++) 73 { 74 if(road[i].bj) 75 { 76 int x=road[i].from,y=road[i].to; 77 hb(x,y); 78 js2++; 79 js1++; 80 ans[js1]=i; 81 } 82 } 83 for(int i=1;i<=m;i++) 84 { 85 int x=road[i].from,y=road[i].to; 86 if(find(x)!=find(y)) 87 { 88 if(!road[i].l) 89 { 90 js2++; 91 } 92 js1++; 93 ans[js1]=i; 94 hb(x,y); 95 } 96 if(js2==t)i=sum,js2=-1; 97 } 98 if(js2!=-1) 99 { 100 printf("no solution\n"); 101 exit(0); 102 } 103 for(int i=1;i<=n-1;i++) 104 { 105 printf("%d %d %d\n",road[ans[i]].from,road[ans[i]].to,road[ans[i]].l); 106 } 107 return 0; 108 }
View Code

Bzoj 3624: [Apio2008]免費道路 (貪心+生成樹)