机试常用算法和题型-图专题

图专题

并查集,寻找父节点,合并模板

/*
这题有个小坑,当然也不算是坑,就是,看起来是求并查集的没错,但是额外附加了一个条件,单个端点只接收一次消息,所以,不能有环出现,排除也很简单,根据树的边数为n-1定则,而且要所有端点必须为同一集合,那么M必须等于N-1,否则,
所有端点无法连通,或出现环,so~题目就简单啦~~
*/

#include 

using namespace std;
//通信系统,要求所有结点都能收到发端消息且不重复


int father[1000];

int findFather(int a){
    int x=a;
    while(x!=father[x]){
        x=father[x];
    }
    while(a!=father[a]){
        int z=a;
        a=father[a];
        father[z]=x;
    }
    return x;

}

void init(int n){
    for(int i=1;i<=n;i++){
        father[i]=i;
    }
}

void Union(int a,int b){
    int A=findFather(a);
    int B=findFather(b);
    if(A!=B){
        father[A]=B;
    }
}

int main()
{
    int n,k,a,b;
    while(cin>>n>>k){
        if(n==0) break;
        init(n);
        for(int i=0;i>a>>b;
            Union(a,b);
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            if(father[i]==i)
                ans++;
        }
        //边只能有n-1条时才不会有环!!
        if(ans==1&&k==n-1)
            cout<<"Yes"<

图的遍历DFS邻接矩阵和邻接表法

//给定一个无向图和所有边,判断这个图是否所有顶点都是联通的
#include 
#include 
using namespace std;

const int maxn=1010;
bool G[maxn][maxn];
bool flag[maxn]={false};
int n;
//n是点数,m是边数
void DFS(int x){
    flag[x]=true;
    for(int i=1;i<=n;i++){
            //由于是无向边true表示可达
        if(flag[i]==false&&G[x][i]==true){
            G[x][i]=false;
            G[i][x]=false;
            //上面这个操作是为了提前清除已经访问边,这样就可以 不用下一组初始化
            DFS(i);
        }
    }
}
int main(){
    int m,d1,d2;
    while(cin>>n>>m){
        if(n==0) break;
        for(int i=0;i>d1>>d2;
            if(G[d1][d2]==false)
                G[d1][d2]=G[d2][d1]=true;
        }
        int number=0;
        memset(flag,0,sizeof(flag));
        for(int i=1;i<=n;i++){
            if(flag[i]==false){
                number++;
                DFS(i);     
            }
        }
        if(number==1){
            printf("YES\n");
        }else{
            printf("NO\n");
        }
    }
    return 0;
}


//邻接矩阵法,其实就要最后的连通块只有一个,有点类似并查集!!

//邻接表法
#include 
#include 
#include 
using namespace std;
const int maxn=1010;
vector Adj[maxn];
bool flag[maxn]={false};
int n;

void DFS(int x){
    flag[x]=true;
    for(int i=0;i>n>>m)
    {
        if(n==0)
            break;
        for(int i=0;i>d1>>d2;
            Adj[d1].push_back(d2);
            Adj[d2].push_back(d1);
        }
        int number=0;
        memset(flag,0,sizeof(flag));
        for(int i=1;i<=n;i++){
            if(flag[i]==false){
                number++;
                DFS(i);
            }
        }
        if(number==1) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

迪杰特斯拉求最短路径长度+从某点到另一点的路径

6 8 0
0 1 1
0 3 4
0 4 4
1 3 2
2 5 1
3 2 2
3 4 3
4 5 3
0 1 5 3 4 6

//迪杰特斯拉最短路劲
#include 
#include 
using namespace std;

const int MAXV=1000; //最大顶点数
const int INF=1000000000; //设置一个很大值表示不可达

int n,m,s,G[MAXV][MAXV]; //n为顶点数,m为边数,s为起点
int d[MAXV]; //起点到各点的最短路径长度
int pre[MAXV];  //prev【v】表示从起点到顶点v的最短路径上v的前一个顶点

bool vis[MAXV]={false};  //标记数组
void Dijkstra(int s){
    fill(d,d+MAXV,INF);  //s到所有点先设置成不可达
    d[s]=0; //这个也很关键,s一开始到自己为0
    for(int i=0;i>n>>m>>s;
    //顶点个数,边数,起点编号
    fill(G[0],G[0]+MAXV*MAXV,INF);
    //对于矩阵如何初始化,学到了
    for(int i=0;i>u>>v>>w;
        G[u][v]=w;
        //输入u,v以及u->v的边权,有向图
    }
    Dijkstra(s);
    //直接算法入口
    for(int i=0;i

优先队列实现地杰斯特拉

#include 
#include 
#include 
using namespace std;

const int maxn=60;
const int INF=0x3fffffff;
int G[maxn][maxn],n,d[maxn];
bool vis[maxn]={false};

struct Node{
    int v,dis;
    //这是有点队列所需要的!!
    bool operator<(const Node &a)const{
        return dis>a.dis;
    }
    //结构定义
    Node(int x,int y){
        v=x;
        dis=y;
    }
};

void Dijkstra(int s){
    fill(d,d+maxn,INF);
    d[s]=0;
    //使用优先队列查找未访问的距离最短结点
    priority_queue q;
    q.push(Node(s,d[s]));
    for(int i=0;i>n){
        cin>>s;
        for(int i=0;i>G[i][j];
            }
        }
        Dijkstra(s);
        for(int i=0;i

prim最小生成树算法

#include 
#include 
#include 
using namespace std;

const int maxn=110;
const int INF=0x3fffffff;
int G[maxn][maxn],d[maxn];
int n;
bool vis[maxn];

int prim()
{
    fill(d,d+maxn,INF);
    memset(vis,0,sizeof(vis));
    d[1]=0;
    int ans=0;
    for(int i=0;i

并查集+最小生成树



#include 
#include 
using namespace std;
#define N 101
int Tree[N];
//关键算法,找到爸爸节结点的标号
int findRoot(int x){
    //查找代表集合的树的根节点,分成两个集合,以此来判断是否要合并两点到一个集合
    if(Tree[x]==-1){
        return x;
    }else{
    //当Tree[x]=1时,表示x爸爸是1,Tree[1]=-1,return Tree[x]=1是一个整体!!
        int tmp=findRoot(Tree[x]);
        //找x的爸爸,递归
        Tree[x]=tmp;
        //tmp确实是x的爸爸,爸爸存了
        return tmp;
    }
}

struct Edge{
//边要有结构体,来进行排序
int a,b;//顶点编号
int cost;
//重载小于运算符很关键!!
bool operator < (const Edge &A) const{
    return cost>n){
        for(int i=1;i<=n*(n-1)/2;i++){
            cin>>edge[i].a>>edge[i].b>>edge[i].cost;
        }
        sort(edge+1,edge+1+n*(n-1)/2);
        for(int i=1;i<=n;i++){
            Tree[i]=-1;
            //初始所有边都处于孤立集合
        }
        int ans=0;

        for(int i=1;i<=n*(n-1)/2;i++){
            int a=findRoot(edge[i].a);
            int b=findRoot(edge[i].b);

            //查找两个顶点的集合信息
            if(a!=b){
                Tree[b]=a;
                //合并两个集合,加入了一个边
                cout<

克鲁斯卡尔最小生成树

6 10
0 1 4
0 4 1
0 5 2
1 2 1
1 5 3
2 3 6
2 5 5
3 4 5
3 5 4
4 5 3
11
  
//克鲁斯卡尔最小生成树算法

#include 
#include <32/bits/stdc++.h>
using namespace std;

const int MAXV=110;
const int MAXE=10010;

struct edge{
    int u,v;  //边的两个端点编号
    int cost; //边权
}E[MAXE];

bool cmp(edge a,edge b){
    return a.cost"<>n>>m;  //顶点数和边数
    for(int i=0;i>E[i].u>>E[i].v>>E[i].cost;
    }
    int ans=kruskal(n,m);

    cout << ans<< endl;
    return 0;
}

  

你可能感兴趣的:(机试常用算法和题型-图专题)