图(数据结构)

图的定义

图是由顶点的有穷非空集合和顶点之间的边的集合组成通常表示为G=(V,E);其中G表示一个图,V是图G中顶点的集合,E是图G中顶点之间的边的集合。

有向图:任意两点之间的边都是有向边(有向边是指,<vi,vj>序偶vi表示弧尾,vj表示弧头,只能从i指向j)

无向图:任意两点之间的边都是无向边(即i,j两点之间的边没有方向可以互达)

简单图:不存在自环

邻接:无向图中任意两个点i,j若这两个点之间存在边(i,j)则称这两个点互为邻接点

依附:有向图中对于任意两个vi,vj若存在弧<vi,vj>则称顶点vi邻接到vj,vj邻接自vi同时称弧<vi,vj>依附于顶点vj,vj。

稠密、稀疏图:边数很少的图称为稀疏图,反之称为稠密图,概念很模糊一般靠相面!

顶点的度:在无向图中,顶点v的度是指依附于该顶点的边数,通常记为TD (v)。

顶点的入度:在有向图中,顶点v的入度是指以该顶点为弧头的弧的数目,记为ID (v);

顶点的出度:在有向图中,顶点v的出度是指以该顶点为弧尾的弧的数目,记为OD (v)。

图的遍历

深度优先遍历:先从一个点开始从这个点未被访问的一个邻接点进行深度优先遍历到底了就返回直到这个点的所有邻接点都被访问然后返回上一层。

广度优先遍历:类似树的层序遍历首先把顶点入队然后把顶点的所有未访问的邻接点入队然后依次出队访问后续节点。

图的存储

邻接矩阵存储/数组表示法:用一个一维数组存储图中的顶点的信息,用一个二维数组表示个顶点之间的邻接关系,存储顶点之间的邻接关系的二维数组称为邻接矩阵。

邻接表:一个头数组来表示节点然后这个头数组对应单链表表示和这个头节点邻接的节点。添加的时候和一般的单链表操作一样头插法插入。

最小生成树

prim算法 是选点一共选n个依据贪心的思想每次都选那不构成环的最短的边所对应的点(边的两个节点一个在已经选的点的集合中另一个点在未选的边的集合中)。需要构建两个数组,一个表示如果当前节点未选那么以这个节点为其中一个端点对应的最短的边的长度是多少,另一个数组表示当前点所对应最短的边的另一个节点是什么

代码:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int Head[10000],Next[10000],ver[10000],po[10000],tot=0;
void inti(){
    tot=0;
    memset(Head,-1,sizeof(Head));
}
void add(int x,int y,int z){
    tot++;
    Next[tot]=Head[x];
    Head[x]=tot;
    ver[tot]=z;
    po[tot]=y;
}
int lowcost[1000],adjvege[1000];
int main(){
    int n,m,e,a[100][100];
    while(cin>>n>>e){
        inti();
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                cin>>a[i][j];
                if(a[i][j]>0&&a[i][j]<100){
                    add(i,j,a[i][j]);
                }
            }
        }
        memset(lowcost,0x3f3f3f3f,sizeof(lowcost));
        for(int i=1;i<=n;i++){
            adjvege[i]=1;
            if(a[1][i]>0&&a[1][i]<100)
                lowcost[i]=a[1][i];
        }
        lowcost[1]=0;
        int k=n-1;
        while(k--){
            int maxx=0x3f3f3f3f,pos;
            for(int i=1;i<=n;i++){
                if(lowcost[i]>0&&lowcost[i]<maxx)
                {
                    maxx=lowcost[i];
                    pos=i;
                }
            }
            cout<<lowcost[pos]<<' ';
            lowcost[pos]=0;
            for(int i=Head[pos];i!=-1;i=Next[i]){
                int y=po[i],z=ver[i];
                if(lowcost[y]>z){
                    lowcost[y]=z;
                    adjvege[y]=pos;
                }

            }
        }
    }
    return 0;
}

Kruskal算法

选n-1条最短边并且这些边不能够成环,所以先按照边权大小排序从前到后选够n-1条边每次选边的时候通过并查集判断这个边加入之后是否会构成回路。

#include <stdio.h>
#include <iostream>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
typedef long long LL;
using namespace std;
typedef long long ll;
int bi[10000],a[1000][1000];
bool v[1000][1000];
int Find(int x){
    int y=x;
    while(bi[y]!=y)
        y=bi[y];
    return y;
}
int main()
{
    int n,m;
    while(cin>>n>>m){
        memset(v,false,sizeof(v));
        for(int i=1;i<=n;i++){
            bi[i]=i;
            for(int j=1;j<=n;j++){
                cin>>a[i][j];
            }
        }
        int p=n-1;
        while(p){
            p--;
            int x,y,maxx=0x3f3f3f3f;
            for(int i=1;i<=n;i++){
                for(int j=i+1;j<=n;j++){
                    if(!v[i][j]&&Find(i)!=Find(j)&&a[i][j]<maxx&&a[i][j]<100){
                        maxx=a[i][j];
                        x=i,y=j;
                        //cout<<maxx<<endl;
                    }
                }
            }
            cout<<x<<' '<<y<<' ';
            v[x][y]=1;
            bi[Find(y)]=Find(x);
        }
        cout<<endl;
    }
}

最短路(代码中都有递归输出路径)

单源最短路 dijkstra

#include <algorithm>
#include <cmath>
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
int n,m;
int f,e;
int a[200][500],b[200],c[200];
bool v[200];
void dfs(int r){
    if(b[r]==-1)
    {
        cout<<'v'<<r<<' ';
        return;
    }
    else{
        dfs(b[r]);
        cout<<'v'<<r<<' ';
    }
}
int main(){

    while(cin>>n>>m>>f>>e){
        memset(a,0x3f3f3f3f,sizeof(a));
        memset(b,-1,sizeof(b));
        memset(v,false,sizeof(v));
        for(int i=0;i<n;i++)
            a[i][i]=0;
        for(int i=1;i<=m;i++){
            int x,y,z;
            cin>>x>>y>>z;
            a[x][y]=z;
        }
        for(int i=0;i<n;i++){
            c[i]=a[f][i];
        }
        c[f]=0;
        v[f]=1;
        for(int w=0;w<n;w++)
        {
            int minn=0x3f3f3f3f,op;
            for(int i=0;i<n;i++)
            {
                if(!v[i]&&c[i]<minn){
                    minn=c[i];
                    op=i;
                }
            }
            if(v[op])continue;
            v[op]=1;
            for(int i=0;i<n;i++){
                if(c[i]>c[op]+a[op][i]&&i!=f){
                    c[i]=c[op]+a[op][i];
                    b[i]=op;
                    //cout<<c[i]<<endl;
                }

            }
        }
        if(c[e]<0x3f3f3f3f&&c[e]>0)
        {
            cout<<c[e]<<endl<<'v'<<f<<' ';
            dfs(e);
            cout<<endl;
        }
        else
        {
            cout<<"no answer"<<endl;
        }

    }

}

floyd

#include <algorithm>
#include <cmath>
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
int n,m;
int a[5000][5000],b[5000][5000];
void dfs(int l,int r){
    if(b[l][r]==-1)
    {
        cout<<'v'<<r<<' ';
    }
    else{
        int p=b[l][r];
        dfs(l,p);
        dfs(p,r);
    }
}
int main(){
    while(cin>>n>>m){
        memset(a,0x3f3f3f3f,sizeof(a));
        memset(b,-1,sizeof(b));
        for(int i=0;i<n;i++)
            a[i][i]=0;
        for(int i=1;i<=m;i++){
            int x,y,z;
            cin>>x>>y>>z;
            a[x][y]=z;
        }
        for(int k=0;k<n;k++){
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    if(a[i][k]+a[k][j]<a[i][j])
                    {
                        a[i][j]=a[i][k]+a[k][j];
                        b[i][j]=k;
                    }
                }
            }
        }
        for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    if(a[i][j]<0x3f3f3f3f&&a[i][j]>0)
                    {
                        cout<<a[i][j]<<' '<<'v'<<i<<' ';
                        dfs(i,j);
                        cout<<endl;
                    }
                }
            }

    }

}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值