最小生成树的水题,在这里讲一下kruskal算法,权当温故:
Kruskal的关键在于对于边权从小到大排序,然后在“排好序的基础上”用并查集判断 E(u , v)上两个顶点u,v 是否在同一个连通分量中,不在,则记录该边权,合并两点。为什么要排序呢?假设从无到有建立一棵最小生成树,则对于从小到大排好序的边集,最先加入合并(加入条件参照上一句话)的N-1条边一定是最优的。
这里,带路径压缩的并查集操作,可以高效地合并、判断两个点是否在同一个连通分量中,时间可视为常数级的。
========Hi~ o(* ̄▽ ̄*)ブ ===========我是呆萌の分割线=================
① HDU1102-Constructing Roads【最小生成树-kruskal(water)】
题意就不翻译了。
关于这题的AC代码如下,不是很规范的Kruskal:
#include
#include
#include
#include
using namespace std;
#define maxn 109
int dis[maxn][maxn], n;
int par[maxn], h[maxn], ans;
struct edge{
int s, t, w;
};
vector
e; void init() { e.clear(); for(int i = 0; i <=n; i++){ par[i] = i; h[i] = 0; } } bool cmp(edge x, edge y) { return x.w < y.w; } int Find(int x) { if(par[x] == x) return x; return par[x] = Find(par[x]); } void Union(int a, int b) { if(h[a] > h[b]){ par[b] = par[a]; } else{ if(h[a] == h[b]) h[b]++; par[a] = par[b]; } } int main() { while(scanf("%d", &n) != EOF){ init(); for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) scanf("%d",&dis[i][j]); int q; scanf("%d", &q); for(int i = 0; i < q; i++){ int a, b; scanf("%d%d", &a, &b); dis[a][b] = dis[b][a] = 0; } //kruskal: for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) { edge x; x.s = i; x.t = j; x.w = dis[i][j]; e.push_back(x); }//初始化边集; sort(e.begin(), e.end(), cmp); ans = 0; for(int i = 0; i < e.size(); i++){ int a, b; a = Find(e[i].s); b = Find(e[i].t); if(a != b) { ans += e[i].w; Union(a, b); } } printf("%d\n", ans); } return 0; }
之前由于忘了把vector clear,WA了N+1次。。。。T^T血的教训惹~~~
②HDU-1863-畅通工程-【基础最小生成树-Kruskal】
AC代码:
#include
#include
#include
#include
using namespace std;
#define maxn 200
int par[maxn], h[maxn], n, m, ans;
struct edge
{
int s, t, w;
};
vector
e; void init() { e.clear(); for(int i = 1; i <= m; i++){ par[i] = i; h[i] = 0; } for(int i = 0; i < n; i++){ int a, b, c; scanf("%d%d%d", &a, &b, &c); edge x; x.s = a; x.t = b; x.w = c; e.push_back(x); } ans = 0; } bool cmp(edge a, edge b) { return a.w < b.w; } int Find(int x) { if(x == par[x]) return x; return par[x] = Find(par[x]); } void Union(int a, int b) { if(h[a] > h[b]) par[b] = par[a]; else{ if(h[a] == h[b]) h[b]++; par[a] = par[b]; } } bool All_Or_Not() { for(int i = 2; i <= m; i++) if(Find(1) != Find(i)) return false; return true; } inline bool kruskal() { sort(e.begin(), e.end(), cmp); for(int i = 0; i < e.size(); i++){ int a, b; a = Find(e[i].s); b = Find(e[i].t); if(a != b){ Union(a, b); ans += e[i].w; } } return All_Or_Not(); } int main() { while(scanf("%d%d", &n, &m) != EOF && n){ init(); bool x = kruskal(); if(x) printf("%d\n", ans); else printf("?\n"); } return 0; }
③HDU-1233-还是畅通工程-【基础最小生成树-Kruskal】
AC代码:
#include
#include
#include
#include
using namespace std;
#define maxn 100
int par[maxn], h[maxn], n, ans;
struct edge
{
int s, t, w;
};
vector
e; void init() { e.clear(); for(int i = 1; i <= n; i++){ par[i] = i; h[i] = 0; } for(int i = 0; i < n*(n-1)/2; i++){ int a, b, c; scanf("%d%d%d", &a, &b, &c); edge x; x.s = a; x.t = b; x.w = c; e.push_back(x); } ans = 0; } bool cmp(edge a, edge b) { return a.w < b.w; } int Find(int x) { if(x == par[x]) return x; return par[x] = Find(par[x]); } void Union(int a, int b) { if(h[a] > h[b]) par[b] = par[a]; else{ if(h[a] == h[b]) h[b]++; par[a] = par[b]; } } inline void kruskal() { sort(e.begin(), e.end(), cmp); for(int i = 0; i < e.size(); i++){ int a, b; a = Find(e[i].s); b = Find(e[i].t); if(a != b){ Union(a, b); ans += e[i].w; } } } int main() { while(scanf("%d", &n) != EOF && n){ init(); kruskal(); printf("%d\n", ans); } return 0; }
④HDU-1875 -畅通工程再续---基础最小生成树★
AC代码:
#include
#include
#include
#include
#include
#include
using namespace std; #define maxn 200 #define INF 0x7fffff struct bri{ double x, y; }; struct node{ double s, t, cost; }; bool cmp(node a, node b){ return a.cost < b.cost; } int c; double ans; vector
ve; bri bridge[maxn]; int par[maxn], h[maxn]; void init(){ ve.clear(); for(int i = 0; i < c; i++){ scanf("%lf%lf", &bridge[i].x, &bridge[i].y); par[i] = i; h[i] = 0; } for(int i = 0; i < c; i++) for(int j = i; j < c; j++){ if(i != j){ double x1 = bridge[i].x, y1 = bridge[i].y; double x2 = bridge[j].x, y2 = bridge[j].y; node n; n.s = i; n.t = j; double dis = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); // cout<<"dis "<
<
= 10 && dis <= 1000) n.cost = 100*dis; else n.cost = INF; ve.push_back(n); } else { node n; n.s = i; n.t = j; n.cost = 0; ve.push_back(n); } } sort(ve.begin(), ve.end(), cmp); // for(int i = 0;i < ve.size(); i++){ // cout<
<<" "<
<<" "<
<
h[b]) par[b] = par[a]; else{ if(h[a] == h[b]) h[b]++; par[a] = par[b]; } } } void kruskal(){ ans = 0; bool flag = false; for(int i = 0; i < ve.size(); i++){ if(ve[i].cost < INF) Union(ve[i]); } for(int i = 1; i < c; i++){ if(Find(0) != Find(i)) { flag = true; break; } } if(flag) printf("oh!\n"); else printf("%0.1lf\n", ans); } int main(){ int T; cin>>T; while(T--){ scanf("%d", &c); init(); kruskal(); } }