1. 程式人生 > >BZOJ 3624 [Apio2008]免費道路:並查集 + 生成樹 + 貪心【恰有k條特殊路徑】

BZOJ 3624 [Apio2008]免費道路:並查集 + 生成樹 + 貪心【恰有k條特殊路徑】

back fail urn 端點 space namespace bzoj stream def

題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=3624

題意:

  給你一個無向圖,n個點,m條邊。

  有兩種邊,種類分別用0和1表示。

  讓你求一棵生成樹,使得這棵樹中恰好有k條0種類的邊。輸出每一條邊的兩端點和種類。

  若無解,則輸出"no solution"。

題解:

  讓0和1分別作兩種邊的邊權。

  步驟:

    (1)先找出必須選的0邊。(優先選1,最大生成樹)

    (2)再將0邊個數加至k。

    (3)補上1邊。

AC Code:

  1 #include <iostream>
  2 #include <stdio.h>
  3
#include <string.h> 4 #include <algorithm> 5 #include <vector> 6 #define MAX_N 20005 7 8 using namespace std; 9 10 struct Edge 11 { 12 int sour; 13 int dest; 14 int len; 15 Edge(int _sour,int _dest,int _len) 16 { 17 sour=_sour; 18 dest=_dest;
19 len=_len; 20 } 21 Edge(){} 22 friend bool operator < (const Edge &a,const Edge &b) 23 { 24 return a.len<b.len; 25 } 26 }; 27 28 int n,m,k; 29 int par[MAX_N]; 30 bool failed=false; 31 vector<Edge> edge; 32 vector<Edge> est;
33 vector<Edge> ans; 34 35 void read() 36 { 37 cin>>n>>m>>k; 38 int a,b,c; 39 for(int i=0;i<m;i++) 40 { 41 cin>>a>>b>>c; 42 edge.push_back(Edge(a,b,c)); 43 } 44 } 45 46 void init_union_find() 47 { 48 for(int i=1;i<=n;i++) 49 { 50 par[i]=i; 51 } 52 } 53 54 int find(int x) 55 { 56 return par[x]==x?x:par[x]=find(par[x]); 57 } 58 59 void unite(int x,int y) 60 { 61 int px=find(x); 62 int py=find(y); 63 if(px==py) return; 64 par[px]=py; 65 } 66 67 bool same(int x,int y) 68 { 69 return find(x)==find(y); 70 } 71 72 void max_tree() 73 { 74 init_union_find(); 75 sort(edge.begin(),edge.end()); 76 int cnt=0; 77 for(int i=edge.size()-1;i>=0;i--) 78 { 79 Edge temp=edge[i]; 80 if(!same(temp.sour,temp.dest)) 81 { 82 cnt++; 83 unite(temp.sour,temp.dest); 84 if(temp.len==0) est.push_back(temp); 85 } 86 } 87 if(cnt!=n-1 || est.size()>k) failed=true; 88 } 89 90 void min_tree() 91 { 92 init_union_find(); 93 int cnt=0; 94 int spe=0; 95 for(int i=0;i<est.size() && spe<k;i++) 96 { 97 Edge temp=est[i]; 98 cnt++; 99 spe++; 100 ans.push_back(temp); 101 unite(temp.sour,temp.dest); 102 } 103 for(int i=0;i<edge.size();i++) 104 { 105 Edge temp=edge[i]; 106 if(!same(temp.sour,temp.dest)) 107 { 108 if(temp.len==0) 109 { 110 if(spe<k) 111 { 112 cnt++; 113 spe++; 114 ans.push_back(temp); 115 unite(temp.sour,temp.dest); 116 } 117 } 118 else 119 { 120 cnt++; 121 ans.push_back(temp); 122 unite(temp.sour,temp.dest); 123 } 124 } 125 } 126 if(cnt!=n-1 || spe!=k) failed=true; 127 } 128 129 void solve() 130 { 131 max_tree(); 132 min_tree(); 133 } 134 135 void print() 136 { 137 if(failed) 138 { 139 cout<<"no solution"<<endl; 140 return; 141 } 142 for(int i=0;i<ans.size();i++) 143 { 144 Edge temp=ans[i]; 145 cout<<temp.sour<<" "<<temp.dest<<" "<<temp.len<<endl; 146 } 147 } 148 149 int main() 150 { 151 read(); 152 solve(); 153 print(); 154 }

BZOJ 3624 [Apio2008]免費道路:並查集 + 生成樹 + 貪心【恰有k條特殊路徑】