考研机试第五天

八.图论

今年408考研数据结构算法题破天荒的考了图的算法,大批学子,也包括我吃了大亏,图的算法不能停留在原理理解上,算法也必须要掌握。

(1)简单并查集的一些操作:

#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN = 1000;
int father[MAXN];
void Initial(int n){
     for(int i = 0;i < n;i++){
        father[i] = i;
     }
     return;//初始化只有一个结点
}
int Find(int x){       //查询
    if(x != father[x]){
       return Find(father[x]);
    }
    return father[x];
}
void Union(int x,int y){    //合并
     x = Find{x};
     y = Find(y);
     if(x != y)
       father[x] = y;
}

(2)查找:路径压缩
是为了更快速的查找一个点的根节点。对于一个集合树来说,它的根节点下面可以依附着许多的节点,因此,我们可以尝试在 find 的过程中,从底向上,如果此时访问的节点不是根节点的话,那么我们可以把这个节点尽量的往上挪一挪,减少数的层数,这个过程就叫做路径压缩。

如下图中,find(4) 的过程就可以路径压缩,让树的层数更少。
在这里插入图片描述节点 4 往上寻找根节点时,压缩第一步,树的层数就减少了一层:
在这里插入图片描述最终得到:
在这里插入图片描述

#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN = 1000;
int father[MAXN];
int height[MAXN];
void Initial(int n){
     for(int i = 0;i < n;i++){
        father[i] = i;
        height[i] = 0;
     }
     return;//初始化只有一个结点
}
int Find(int x){       //查询
    if(x != father[x]){
       return Find(father[x]);
    }
    return father[x];
}
void Union(int x,int y){    //合并
     x = Find{x};
     y = Find(y);
     if(x != y){
        if(height[x] < height[y]){
           father[x] = y;
        }else if(height[x] > height[y]){
           father[y] = x;
        else{
           father[y] = x;//father[x] = y也可以
           height[x] +=1;
        }
    }           
}

(3)连通图
无向图-极大连通子图

前面代码同上
int main(){
    int n,m;//n为顶点,m为边
    while(scanf("%d%d",&n,&m) != EOF){
         if(n == 0 && m ==0){
            break;
         }
         Initial(n);//初始化循环内为<=n
         while(m--){
             int x,y;
             scanf("%d%d",&x,&y);
             Union(x,y);
         }
         int conmponrt = 0;
         for(int i = 1;i <= n;++i){
            if(i == Find(i)){
               component++;
             }
          }
          if(component == 1)
             printf("YES\n");
          else printf("NO\n");
 }
         

(4)最小生成树(MST)
生成树:连通图的极小连通子图
MST:带权图所有生成树中边权值之和最小的那一颗

问题10:某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府目标是使全省任何两个村庄间都可以实现公路交通,并要求铺设的公路总长度最短,请计算最小的公路总长度。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 100;

struct Edge{
      int from;
      int to;
      int length;
      bool operator <(const Edge &e)const{
           return length < e.length;
     }
};

Edge edge[MAXN*MAXN];
int father[MAXN];
int height[MAXN];

void Initial(int n){
     for(int i = 0;i < n;i++){
        father[i] = i;
        height[i] = 0;
     }
     return;//初始化只有一个结点
}
int Find(int x){       //查询
    if(x != father[x]){
       return Find(father[x]);
    }
    return father[x];
}
void Union(int x,int y){    //合并
     x = Find{x};
     y = Find(y);
     if(x != y){
        if(height[x] < height[y]){
           father[x] = y;
        }else if(height[x] > height[y]){
           father[y] = x;
        else{
           father[y] = x;//father[x] = y也可以
           height[x] ++;
        }
    }           
    return;
}
int Kruskal(int n,int edgeNumber){
    Initial(n);
    srot(edge,edge+edgeNumber);
    int sum = 0;
    for(int i = 0;i < edgeNumber;++i){
        Edge current = edge[i];
        if(Find(current.from != Find(current.to)){
           Union(current.from,current.to);
           sum += current.length;
        }
    }
    return sum;
 }
 int main(){
     int n;
     while(scanf("%d",&n) != EOF){
          if(n == 0) break;
          int edgeNUmber = n*(n-1)/2;
          for(int i = 0;i < edgeNumber;++i){
             scanf("%d%d",&edge[i].from,&edge[i].to,&edge[i].length);
          }
          int answer = Kruskal(n,edgeNumber);
          printf("%d\n",answer);
     }
     return 0;
}

无论哪种,prim+heap都是性能最佳的算法,但实现起来较复杂
时间复杂度:kruskal:O(ElogE)
prim:O(V^2)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值