图论算法大集锦

1.图的存储:

  (1)邻接矩阵:

      

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define MAXN 0x7fffffff//没有路径(边的长度为极限);
#define maxn 9999//数据边的最大值;
#define MAX 0x7fffffff/3//两极限边相加可能超过int 大小;
using namespace std;

int m,n;//点的个数和边的个数;
int s[maxn][maxn];

void adjacency_matrix_storage()
{
    cin>>m>>n;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
            s[i][j]=MAXN;
    for(int i=1;i<=n;++i)
    {
        int s1,s2,weight;
        cin>>s1>>s2>>weight;
        s[s1][s2]=weight;
        //s[s2][s1]=weight; 如果是无向边就加上这句;
    }

} 

int main()
{
    adjacency_matrix_storage();
    //后面是其他操作;
    return 0;
}

邻接矩阵存储

  (2)邻接表:

      

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define maxn 99999
#define MAXN 0x7fffffff/3
using namespace std;

struct node
{
    int a,b,w,next;
};
node edge[maxn];//用邻接表存储边; 

int head[maxn],sum=1;//存储顶点,sum为下标;
int m,n; //顶点个数和边的个数; 

void push(int a,int b,int c)
{
    edge[sum].a=a;
    edge[sum].b=b;
    edge[sum].w=c;
    edge[sum].next=head[a];
    head[a]=sum++;
}

void Initialization()
{
    sum=1;
    for(int i=1;i<=m*n;++i)
    {
        head[i]=-1;//用-1作为标志表明链表的结束;
        edge[i].w=MAXN;
    }
}

int main()
{
    int i,j;
    cin>>m>>n;
    Initialization();
    for(i=1;i<=n;++i)
    {
        int a,b,c;
        cin>>a>>b>>c;
        push(a,b,c);//有向边;
    }
    cin>>j;
    cout<<endl;
    for(int k=head[j];k!=-1;k=edge[k].next)//调用顶点J相连的每一条边;
    {
        int l=edge[k].b;//L和顶点J的关系是:L和J之间存在一条从J指向L的有向线段;
        cout<<j<<‘ ‘<<l<<endl;
    } 

    //······其他操作;
    return 0;
}

邻接表存储

一般情况下使用邻接表存储会降低使用空间大小和有效节约时间;但如果是比较稠密的图这两种方式就区别不大了;

2.图的遍历:

  (1)DFS:

      

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define maxn 99999
#define MAXN 0x7fffffff/3
using namespace std;

struct node
{
    int a,b,w,next;
};
node edge[maxn];//用邻接表存储边; 

int head[maxn],sum=1;//存储顶点,sum为下标;
int m,n; //顶点个数和边的个数;
bool visit[maxn]={false}; 

void push(int a,int b,int c)
{
    edge[sum].a=a;
    edge[sum].b=b;
    edge[sum].w=c;
    edge[sum].next=head[a];
    head[a]=sum++;
}

void Initialization()
{
    sum=1;
    for(int i=1;i<=m*n*2;++i)
    {
        head[i]=-1;//用-1作为标志表明链表的结束;
        edge[i].w=MAXN;
        visit[i]=false;
    }
}

void DFS(int sum)
{
    visit[sum]=true;
    if(edge[sum].b!=0)
    cout<<"-->"<<edge[sum].b;
    for(int k=head[sum];k!=-1;k=edge[k].next)//调用顶点J相连的每一条边;
        if(!visit[edge[k].b])
            DFS(edge[k].b);
}

int main()
{
    int i,j;
    cin>>m>>n;
    Initialization();
    for(i=1;i<=n;++i)
    {
        int a,b,c;
        cin>>a>>b>>c;
        push(a,b,c);//有向边;
    }
    cin>>j;
    cout<<endl;
    cout<<j;
    DFS(j);
    //······其他操作;
    return 0;
}

DFS邻接表

  (2)BFS:

      

#include<iostream>
#include<queue>
#include<cstdio>
#include<cstdlib>
#define maxn 99999
#define MAXN 0x7fffffff/3
using namespace std;

struct node
{
    int a,b,w,next;
};
node edge[maxn];//用邻接表存储边; 

int head[maxn],sum=1;//存储顶点,sum为下标;
int m,n; //顶点个数和边的个数;
bool visit[maxn]={false},vis[maxn]={false}; 

void push(int a,int b,int c)
{
    edge[sum].a=a;
    edge[sum].b=b;
    edge[sum].w=c;
    edge[sum].next=head[a];
    head[a]=sum++;
}

void Initialization()
{
    sum=1;
    for(int i=1;i<=m*n*2;++i)
    {
        head[i]=-1;//用-1作为标志表明链表的结束;
        edge[i].w=MAXN;
        visit[i]=vis[i]=false;
    }
}

void DFS(int sum)
{
    visit[sum]=true;
    if(edge[sum].b!=0)
    cout<<"-->"<<edge[sum].b;
    for(int k=head[sum];k!=-1;k=edge[k].next)//调用顶点J相连的每一条边;
        if(!visit[edge[k].b])
            DFS(edge[k].b);
}

void BFS(int sum)
{
    queue<int>que;
    que.push(sum);
    vis[sum]=true;
    cout<<sum;
    while(!que.empty())
    {
        int su=que.front();
        que.pop();

        for(int k=head[su];k!=-1;k=edge[k].next)//调用顶点J相连的每一条边;
        if(!vis[edge[k].b])
        {
            que.push(edge[k].b);
            vis[edge[k].b]=true;
            cout<<"-->"<<edge[k].b;
        }
    }
}

int main()
{
    int i,j;
    cin>>m>>n;
    Initialization();
    for(i=1;i<=n;++i)
    {
        int a,b,c;
        cin>>a>>b>>c;
        push(a,b,c);//有向边;
    }
    cin>>j;
    cout<<endl;
    cout<<j;
    DFS(j);
    cout<<endl<<"******************"<<endl;
    BFS(j);
    //······其他操作;
    return 0;
}

BFS邻接表

一般来说这两者都有不小的缺点:DFS深度优先搜索会调用大量的栈空间,很容易爆栈;

而BFS内存耗费量大(需要开大量的数组单元用来存储状态)

总而言之,这两者都在时空上有很大的局限性;慎用!

3.求最短路径

  (1)Flyoed:

      

#include <cstdio>
#include <iostream>
#define MAXN 99999999
using namespace std;

int dis[10][10],k,i,j,n,m;

int main()
{

    cin >> n >> m;

    for(i=1; i<=n; i++)
        for(j=1; j<=n; j++)
            if(i==j) dis[i][j]=0;
            else dis[i][j]=MAXN;
    for(i=1; i<=m; i++)
    {
        int a,b,c;
        cin >> a >> b >> c ;
        dis[a][b]=c;
    }
    for(k=1; k<=n; k++)
        for(i=1; i<=n; i++)
            for(j=1; j<=n; j++)
                if(dis[i][j]>dis[i][k]+dis[k][j] )
                    dis[i][j]=dis[i][k]+dis[k][j];
    int start,end;
    cin >> start >> end ;
    cout << dis[start][end] <<endl;
    return 0;
}

Flyoed

  (2)Dijkstra:

      

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
const int MAXN = 1010;
const int INF = 999999999;
int n, k;
int map[MAXN][MAXN];
bool visit[MAXN];
int pre[MAXN];
int dist[MAXN];

void init()
{
    memset(visit, false, sizeof(visit));
    for (int i = 1; i <= n; ++i){
        for (int j = 1; j <= n; ++j)
            map[i][j] = INF;
        pre[i] = i;
        dist[i] = INF;
    }
}
void Dijkstra(const int v)
{
    int i, j;
    int minValue, minNode;

    dist[1] = 0;
    visit[1] = true;

    for (i = 2; i <= n; ++i){
        if (map[1][i] != INF){
            dist[i] = map[1][i];
            pre[i] = 1;
        }
    }

    for (i = 1; i <= n; ++i)
    {
        minValue = INF;
        minNode = 0;

        for (j = 1; j <= n; ++j){
            if (!visit[j] && minValue > dist[j]){
                minNode = j;
                minValue = dist[j];
            }
        }
        if (minNode == 0)
            break;

        visit[minNode] = true;
        for (j = 1; j <= n; ++j)
        {
            if (!visit[j] && map[minNode][j] != INF && dist[j] > dist[minNode] + map[minNode][j])
            {
                dist[j] = dist[minNode] + map[minNode][j];
                pre[j] = minNode;
            }
        }

        if (minNode == v)
            break;
    }
}

Dijkstra

  (3)SPFA:

      

long long SPFA(int st)
{
    for(int i=1;i<=n;i++)
        sp[i]=inf;
    sp[1]=0;
    queue<int> q;
    q.push(st);
    while(!q.empty())
    {
        int kai=q.front();q.pop();
        for(int i=H[kai];i!=-1;i=E[i].next)
        {
            if(sp[E[i].v]>E[i].count+sp[kai]){
                sp[E[i].v]=E[i].count+sp[kai];
                q.push(E[i].v);
            }
        }
    }
    long long ans=0;
    for(int i=1;i<=n;i++)
        ans+=sp[i];
    return ans;
} 

void spfa(int s,int dis[])
{
    int i,pre[N];
    bool used[N];
    queue<int> q;
    memset(used,0,sizeof(used));
    memset(pre,-1,sizeof(pre));
    for(i=0; i<N; i++)
        dis[i]=inf;
    dis[s]=0;
    used[s]=true;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        used[u]=false;
        for(i=0; i<map[u].size(); i++)
        {
            Node p=map[u][i];
            if(dis[p.v]>dis[u]+p.len)
            {
                dis[p.v]=dis[u]+p.len;
                pre[p.v]=u;
                if(!used[p.v])
                {
                    used[p.v]=true;
                    q.push(p.v);
                }
            }
        }
    }
}  

SPFA

三者的时间复杂度依次为:O(n^3),O(n^2),O(KE),其中E是边数,K是常数,平均值为2,图越稠密,K越大;

其中F·····和D·······算法比较的稳定,可是很慢啊,SPFA一般情况下比较快,可是一但图很稠密,就退化到N^2的复杂度;

但还是SPFA用的最多,也最好用,建议做最短路径的题用SPFA;

时间: 2024-09-28 18:25:25

图论算法大集锦的相关文章

排序算法大集锦_二路归并排序_2&3(分治思想)

第一段代码和合并排序差不多,用它来和第二段代码--二路归并排序作对比. 这一系列博客的特点就是--给出每趟排序的结果 本来想着好好写一下过程,弄个图片什么的,不过觉得网上的解析太多了,都比较好,所以这些博客就算是对自己的总结吧. #include <stdio.h> #include <limits.h> #include <malloc.h> void merge(int *m, int x, int y, int z) { int b1,b2,i,j,k; b1=y

排序算法大集锦_各种排序算法性能比较

对10000个1-10000的随机数进行排序,并显示出运行时间 数组是用以前用VC++&MatLab生成的,比较长...哈哈,感受一下计算机的速度! #include <stdio.h> #include <string.h> #include <stdlib.h> #include <limits.h> #include <malloc.h> #include <time.h> int a[10000]={ 5282,330

排序算法大集锦_线性时间_计数排序

这个之前在<编程珠玑>上面看到过,当时就感觉特别神奇! 速度突破了其他排序算法的下限 后来在<算法导论>上面又看到了,感触颇深!所以一定好好啃透<算法导论> 这一系列博客的特点就是--给出每趟排序的结果 本来想着好好写一下过程,弄个图片什么的,不过觉得网上的解析太多了,都比较好,所以这些博客就算是对自己的总结吧. #include <stdio.h> #include <string.h> int a[10]={2,8,6,7,3,3,1,9,6

排序算法大集锦_插入类——直接插入排序

这一系列博客的特点就是--给出每趟排序的结果 本来想着好好写一下过程,弄个图片什么的,不过觉得网上的解析太多了,都比较好.<算法导论>上面那个比喻,比做打扑克牌的插入新牌,就比较形象.所以这些博客就算是对自己的总结吧. #include <stdio.h> void InsertSort(int *m, int n) { int i,j,temp; for(i=1;i<n;i++) { temp=m[i]; j=i-1; while(j>=0 && te

排序算法大集锦_交换类——快速排序

感觉<算法导论>上面的那个例子要更容易理解,因为那个最起码比较直观! #include <stdio.h> int a[10]={2,8,5,7,4,3,1,9,6,10}; void QuickSort(int m, int n) { int s,begin,end; if(m>n) return; begin=m; end=n; s=a[m]; while(begin!=end) { while(a[end]>=s && begin<end)

排序算法大集锦_选择类——直接选择排序

这一系列博客的特点就是--给出每趟排序的结果 本来想着好好写一下过程,弄个图片什么的,不过觉得网上的解析太多了,都比较好,所以这些博客就算是对自己的总结吧. #include <stdio.h> void SelectSort(int *m, int n) { int i,j,k,temp; bool flag; for(i=0;i<n-1;i++) { k=i; flag=true; for(j=i+1;j<n;j++) if(m[j]<m[k]) k=j; if(k!=i

排序算法大集锦_合并排序_1(分治思想)

这一系列博客的特点就是--给出每趟排序的结果 本来想着好好写一下过程,弄个图片什么的,不过觉得网上的解析太多了,都比较好,所以这些博客就算是对自己的总结吧. #include <stdio.h> #include <limits.h> #include <malloc.h> int a[10]={2,8,5,7,4,3,1,9,6,10}; void merge(int *m, int x, int y, int z) { int b1,b2,i,j,k; b1=y-x

排序算法大集锦_插入类——希尔(shell)排序

这一系列博客的特点就是--给出每趟排序的结果 本来想着好好写一下过程,弄个图片什么的,不过觉得网上的解析太多了,都比较好,所以这些博客就算是对自己的总结吧. #include <stdio.h> void ShellSort(int *m, int n) { int i,flag,gap; for(gap=n;gap!=1;) { gap/=2; do { flag=0; for(i=0;i<n-gap;i++) if(m[i]>m[i+gap]) { m[i]=m[i]^m[i+

排序算法大集锦_交换类——冒泡排序

冒泡排序是在高中时代就接触到的一种排序,较为简单,相对其它排序要容易理解 这一系列博客的特点就是--给出每趟排序的结果 本来想着好好写一下过程,弄个图片什么的,不过觉得网上的解析太多了,都比较好,所以这些博客就算是对自己的总结吧. #include <stdio.h> void BubbleSort(int *m, int n) { int i,j; for(i=0;i<n-1;i++) { for(j=1;j<n-i;j++) if(m[j]<m[j-1]) { m[j]=