BZOJ 3624 [Apio2008]免费道路:并查集 + 生成树 + 贪心恰有k条特殊路径
Posted Leohh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3624 [Apio2008]免费道路:并查集 + 生成树 + 贪心恰有k条特殊路径相关的知识,希望对你有一定的参考价值。
题目链接: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条特殊路径的主要内容,如果未能解决你的问题,请参考以下文章
Bzoj 3624: [Apio2008]免费道路 (贪心+生成树)
BZOJ 3624: [Apio2008]免费道路 [生成树 并查集]