基础最小生成树代码留存

这篇博客主要介绍了Kruskal算法实现最小生成树的基本思路,强调了边权排序和并查集在算法中的关键作用。通过路径压缩的并查集可以高效地判断边是否构成环,并给出几个HDU在线判题系统的AC代码示例。
摘要由CSDN通过智能技术生成


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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值