圖(數據結構)

圖的定義

圖是由頂點的有窮非空集合和頂點之間的邊的集合組成通常表示爲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;
                    }
                }
            }

    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章