基础最小生成树代码留存


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


你可能感兴趣的:(图论,Water,Problem)