最小生成树的水题,在这里讲一下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();
}
}