第六章 图笔记

上次老师检查笔记时,我的第五章笔记还没有整理完整,后来又进行了补充,请老师再看一看:https://www.cnblogs.com/dean-SunPeishuai/p/10674881.html

                                                                                          图

  1.邻接矩阵实现

   邻接矩阵的构建:

Mgraph<T>::Mgraph(T a[], int n, int e)//邻接矩阵的构建
{
    vertex = n;
    arcnum = e;
    for (int i = 0; i < vertexnum; i++)//初始化顶点
    {
        vertex[i] = a[i];
    }
            memset(arc,0,sizeof(arc));
            for (int i = 0; i < arcnum; i++)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                    arc[x][y]=1;
                    arc[y][x]=1;
            }

}

 深度优先搜索:

template<class T>
void Mgraph<T>::DFS(int v)
{
    cout << vertex[v] << " "; visit[v] =1;
    for (int i = 0; i < vertexnum; i++)
    {
        if (arcnum[v][i] == 1 && visit[i] == 0) DFS(i);
    }

}

广度优先深搜:

template<class T>
void Mgraph<T>::BFS(int v)
{
    int Queue[MaxSize];
    int front = rear = -1;//借助数组模拟队列先进先出的功能
    cout << vertex[v] << " "; visit[v] = 1;
    Queue[++rear] = 1;
    while (front != rear)
    {
        v = queue[++front];
        for (int i = 0; i < vertexnum; i++)
        {
            if (visit[i] == 0 && arc[v][i] == 1)
            {
                cout << vertex[i] << " ";
                visit[i] = 1;
                Queue[++rear] = i;
            }
        }
    }
}

 2.邻接链表实现(未定义visit[],仅将代码流程过一遍)

#include<bits/stdc++.h>
using namespace std;
template<class T>
struct ArcNode//边表
{
    int adjvex;
    ArcNode *next;
};
template<class T>//顶点表
struct VertexNode
{
    T vertex;
    ArcNode *firstedge;
};
const int MaxSize = 100;    //图的最大顶点数
template <class T>
class ALGraph
{
public:
    ALGraph(T a[], int n, int e);
    ~ALGraph;
    void DFSTraverse(int v);
    void BFSTraverse(int v);
private:
    VertexNode adjlist[MaxSize];
    int vertexNum, arcNum;
};
/*         构建函数          */
template<class T>
ALGraph<T>::ALGraph(T a[], int n, int e)
{
    vertexNum = n; arcNum = e;
    for (int i = 0; i < vertexNum; i++)
    {
        
        adjlist[i].vertex = a[i];
        adjlist[i].firstedge = NULL;
    }
    for (int j = 0; j < arcNum; j++)
    {
        int x, y;
        cin >> x >> y;
        s = new ArcNode<T>;//生成邻接点序号y的边表节点s
        s->adjvex = y;//j将边表s插入到第x个边表的头部
        s->next = adjlist[x].firstedge;
        djlist[x].firstedge = s;
    }
}
/*       深度优先遍历          */
template<class T>
void ALGraph<T>::DFSTraverse(int v)
{
    cout << adjlist[v].vertex;
    visit[v] = 1;
    ArcNode<T> p = adjlist[v].firstedge;
    while (p)
    {
        int j = p.adjvex;
        if (vistt[j] == 0) DFSTraverse(j);
        p = p->next;
    }

}
/*         广度优先搜索          */
template<class T>
void ALGraph<T>::BFSTraverse(int v)
{
    int Q[MaxSize];
    memset(Q, 0, sizeof(Q));
    int front = rear = -1;
    cout << adjlist[v].vertex;
    visit[v] = 1;
    Q[++rear] = v;
    while (front!=rear)
    {
        v = Q[++front];
        ArcNode<T> p = adjlist[v].firstedge;
        while (p)
        {
            int j = p->adjvex;
            if (visit[j] == 0)
            {
                cout << adjlist[j].vertex;
                visit[j] = 1;
                Q[++rear] = j;
                
            }
            p = p->next;
        }
    }
}



int main()
{

}

 prime算法:自己之前的理解

     Prime算法的思想是枚举各个点能够到到达的所有路,找出他们之间最短的,首先选择一个顶点加入生成树,然后找出一条边加入到生成树,重复n-1次,直到把所有的节点都加入到生成树中,在此算法里面需要一个dis数组,不过它和迪杰斯特拉算法的不同之处在于,迪杰斯特拉的思想是dis[i]表示从1到顶点i的最小距离,而Prime算法中,dis[i]代表每个项点到离他最近的点的距离,然后通过松弛操作得出结果 ,时间复杂度为O(N^2)。

 求最小生成树Prime模板:

using namespace std;
int dis[108],map1[108][108],vis[108];
#define INF 0x3f3f3f3f
int n;
int  prime()
{
    memset(vis,0,sizeof(vis));
    int ans=0,cnt=0,k=0,minn=INF;
    vis[1]=1;
    cnt++;
    while(cnt<n)
    {
        minn=INF;///就这个地方忘记了,然后、、、、、、
        for(int i=1;i<=n;i++)//查找没有访问过的,距离当前最小生成树最小的边
        {
            if(!vis[i]&&dis[i]<minn)
            {
                minn=dis[i];
                k=i;//标记下来边的临界点
            }
        }
        cnt++;
        vis[k]=1;//标记访问过的点
        ans+=dis[k];
 
       for(int j=1;j<=n;j++)///由于新加的点,其他的点到最下生成树的点距离可能变短,更新哪些到最小生成树变短的点
       {
          if(!vis[j]&&dis[j]>map1[k][j])
            dis[j]=map1[k][j];
       }
    }
    return ans;
}
--------------------- 
作者:sean(SunPeishuai) 
来源:CSDN 
原文:https://blog.csdn.net/SunPeishuai/article/details/84719169 
版权声明:本文为博主原创文章,转载请附上博文链接!

poj:6:prim算法求最小生成树

题目: 连接:http://sdau.openjudge.cn/graph/6/

分析:裸的最小生成树

代码:

#include<bits/stdc++.h>
using namespace std;
int dis[108], map1[108][108], vis[108];
#define INF 0x3f3f3f3f
int n, e;
void  prime()
{
    memset(vis, 0, sizeof(vis));
    int ans = 0, cnt = 0, k = 0, minn = INF;
    vis[1] = 1;
    cnt++;
    while (cnt < n)
    {
        minn = INF;///就这个地方忘记了,然后、、、、、、
        for (int i = 1; i <= n; i++)
        {
            if (!vis[i] && dis[i] < minn)
            {
                minn = dis[i];
                k = i;
            }
        }
        cout << minn << " ";
        cnt++;
        vis[k] = 1;
        ans += dis[k];
        for (int j = 1; j <= n; j++)///由于新加的点,其他的点到最下生成树的点距离可能变短,更新哪些到最小生成树变短的点
        {
            if (!vis[j] && dis[j] > map1[k][j])
                dis[j] = map1[k][j];
        }
    }
}
int main()
{

    scanf("%d%d", &n, &e);
    memset(dis, INF, sizeof(dis));
    memset(map1, INF, sizeof(map1));
    for(int i=1;i<=n;i++)
        for (int j = 1; j <= n; j++)
        {
            scanf("%d", &map1[i][j]);
        }
    for (int i = 1; i <= n; i++)
    {
        dis[i] = map1[1][i];
    }
    prime();
    cout << endl;
    system("pause");
    return 0;
}

 Kruskal算法思想:

   此算法是求最小生成树的另一只种算法,首先,将图上面的权值按照从小到大的顺序排列,最终连成n-1条边。按照排列好的顺序,在连线的过程中可能会遇到已经连通的点,需要用并查集进行辅助判断两个分量上的点是否已经联通。

此处为Kruskal以前自己总结的模板:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define N 100+20
#define M 100000+20
using namespace std;
struct node
{
    int x;
    int y;
    int v;
}map1[5008];
int n,m,fa[5008];
int fin(int u)
{
    if(fa[u]==u)
        return u;
    else
    {
        fa[u]=fin(fa[u]);///并查集的路径压缩
        return fa[u];
    }
}
int mix(int a,int b)
{
    int f1=fin(a);
    int f2=fin(b);
    if(f1!=f2)
    {
        fa[f2]=f1;
        return 1;
    }
    return 0;
}
int cmp(node a,node b)
{
    return a.v<b.v;
}
int main()
{
   while(scanf("%d",&n)!=EOF)
   {
       int ans=0,cnt=0;
       if(n==0) break;
       m=n*(n-1)/2;
       memset(fa,0,sizeof(fa));///
       for(int i=1;i<=m;i++)
       {
           scanf("%d%d%d",&map1[i].x,&map1[i].y,&map1[i].v);
       }
       sort(map1+1,map1+m+1,cmp);
       for(int i=1;i<=n;i++)///并查集的初始化
       {
           fa[i]=i;
       }
 
 
       //kruskal算法
       for(int i=1;i<=m;i++)///从小到达枚举边
       {
           if(mix(map1[i].x,map1[i].y))///若加的边构不成环则加上
           {
               cnt++;
               ans+=map1[i].v;
           }
           if(cnt==n-1) break;
       }
       printf("%d\n",ans);
   }
   return 0;
}
View Code

 

5:kruskal算法求最小生成树

题目:连接http://sdau.openjudge.cn/graph/5/

分析:

代码:

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define N 100+20
#define M 100000+20
using namespace std;
struct node
{
    int x;
    int y;
    int v;
}map1[5008];
int n, m, fa[5008], map2[1000][1000];
int fin(int u)//并查集查找
{
    if (fa[u] == u)
        return u;
    else
    {
        fa[u] = fin(fa[u]);///并查集的路径压缩
        return fa[u];
    }
}
int mix(int a, int b)//连接
{
    int f1 = fin(a);
    int f2 = fin(b);
    if (f1 != f2)
    {
        fa[f2] = f1;
        if(a<b)//在此处输出一条边的两个连接点
        cout << a << " " << b << " ";
        else {
            cout << b<< " " << a<< " ";
        }
        return 1;
    }
    return 0;
}
int cmp(node a, node b)
{
    return a.v < b.v;
}
int main()
{
    int n, e, v,cnt=0;
    scanf("%d%d", &n, &e);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
        {
            scanf("%d", &map2[i][j]);
        }
    int t = 1;
    for (int i =1; i <= n-1; i++)//此处为适应模板做的适当处理
        for (int j = i+1; j <=n; j++)
        {
            map1[t].x = i; map1[t].y = j; 
            if(map2[i][j] != 0 && map2[i][j] != 100){
                map1[t].v = map2[i][j];
                t++;
            }

        }
    sort(map1 + 1, map1 + 1 + e, cmp);
    for (int i = 1; i <= n; i++) fa[i] = i;//并查集的初始化
    /*       kruskal算法      */
    for (int i = 1; i <= e; i++)//从小到大枚举边 
    {
        if(mix(map1[i].x, map1[i].y))
       {
            cnt++;
       }
        if (cnt == n - 1) break;
    }
    cout << endl;
    system("pause");
    return 0;
}

 dijkstra求最短路径:‘

题目:http://sdau.openjudge.cn/graph/1/

分析:直接套模板就行,自己之前刘汝佳的模板忘记怎么用输出路径了,尴尬。就从网上扒了一个模板改的。

代码:

#include<stdio.h>
#include<string.h>
#define INF 1e9
#define maxn 1001
bool vis[maxn];
int adj[maxn][maxn],dis[maxn],pre[maxn];//pre[]记录前驱
int n, m;
void dijkstra(int v)
{
    int i, j, u , min;
    for(i=0;i<n;i++)///v到所点的距离初始化
    {
         dis[i]=adj[v][i];
         vis[i]=0;
         if(i!=v&&adj[v][i]!=INF)pre[i] = v;
         else pre[i] = -1;
    }
    vis[v]=1;dis[v]=0;
    for(i=0;i<n;i++)
    {
        min = INF;
        for(j=0;j<n;j++)
        {
            if(!vis[j]&&min > dis[j])
            {
                min = dis[j];
                u = j;
            }
        }
        if(min == INF)break;
        vis[u]=1;
        for(j=0;j<n;j++)
        {
            if(!vis[j]&&adj[u][j]!=INF&&dis[u]+adj[u][j]<dis[j])
            {
                dis[j] = adj[u][j] + dis[u];
                pre[j] = u;
            }
        }
    }
}
int main()
{
        int start,end1, x, y, w;
        scanf("%d%d",&n,&m);///n个节点,m条边
        scanf("%d%d",&start,&end1);///起点--->终点
        for(int i=0;i<n;i++)///初始化
        {
            for(int j=0;j<n;j++)
                if(i==j)adj[i][j]=0;
                else adj[i][j] = INF;
        }
        while(m--)
        {
            scanf("%d%d%d",&x,&y,&w);
            adj[x][y] = w;
        }
        dijkstra(start);///起点
        if(dis[end1]==1e9){
            printf("no answer\n");
        }else{
        printf("%d\n",dis[end1]);  //以下为输出路径
        int p, len=0, ans[maxn];
        p = end1;
        while(p!=0)
        {
            ans[len++] = p;
            p = pre[p];

        }
        printf("v%d ",start);
        for(int i=len-1;i>=0;i--)
            printf("v%d ",ans[i]);
        }
    return 0;
}

 floyd求最短路径

题目:http://sdau.openjudge.cn/graph/2/

分析:

代码:

/*floyd算法,打印路径模板*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
#define N 1005
#define INF 0x3f3f3f3f

using namespace std;

int mapp[N][N], path[N][N];//path[i][j]的含义:从i到j的路径中,i的下一个点。
int n,m;//顶点数,边数
void init()
{
    int i, j;
    for (i = 0; i < n; i++)
        for (j = 0; j <n; j++)
        {
            if (i == j)    mapp[i][j] = 0;
            else mapp[i][j] = INF;
        }
}
void floyd()
{
    for (int i = 0; i <N; ++i)
    {
        for (int j = 0; j < N; ++j)
        {
            if (mapp[i][j] == INF) path[i][j] = -1;///i不能直接到j
            else path[i][j] = j;///i到j路径的下一个点为j
        }
    }
    int i, j, k;
    for (k = 0; k <n; k++)
    {
        for (i = 0; i < n; i++)
        {
            for (j = 0; j < n; j++)
            {
                if (mapp[i][k] < INF && mapp[k][j] < INF && mapp[i][j] > mapp[i][k] + mapp[k][j])
                {
                    mapp[i][j] = mapp[i][k] + mapp[k][j];
                    path[i][j] = path[i][k];//从i到j的下一个顶点为i到k的下一个顶点
                }
            }
        }
    }
}

int main()
{
        scanf("%d%d", &n, &m);
        int a, b, c;
        init();

        for (int i = 0; i < m; i++)
        {
            scanf("%d%d%d", &a, &b, &c);
            mapp[a][b]=c;//无向图
        }
        floyd();//打印路径
        int T, start, end;
        for(int i=0;i<n;i++)
        {
          for(int j=0;j<n;j++)
          {
            if(i!=j)
            {
                start=i;
                end=j;
                if(mapp[start][end]==INF)
                {
                    cout<<"no answer"<<endl;
                }
                else
                {
                    printf("%d ",mapp[start][end]);
                    int tmp = start;
                    printf("v%d ",start);
                    while (tmp!= end)
                    {
                      printf("v%d ",path[tmp][end]);
                      tmp = path[tmp][end];
                    }
                }
                 printf("\n");
              }
          }

        }
    return 0;
}

 

转载于:https://www.cnblogs.com/dean-SunPeishuai/p/10896899.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值