Day8——图论

本文介绍了图论的基础知识,包括有向图和无向图,以及图的存储方式——邻接矩阵和邻接链表。重点讲解了最小生成树的Prim算法和Kruskal算法,包括它们的原理、代码实现和复杂度分析。同时,通过四个具体的图论题目,展示了区间查询、最大承重、零钱问题和生成树计数的解决思路和代码实现。
摘要由CSDN通过智能技术生成

最后一天集训,讲了图论。是一个女老师讲的。最后一天上的是图论。据老师说的,她要是有良心会到最后一天讲图论吗?所以,图论好难啊啊啊啊。


图分为有向图和无向图。
图的存储方式有两种
1) 邻接矩阵
2) 邻接链表
邻接矩阵在数据较小时可以使用,但是如果数据大时,很可能会浪费大量空间,所以一般还是使用邻接链表。


图的最小生成树:

求图的最小生成树大体有两种。
一种是Prim算法:
具体代码实现如下:

int edge[1005][1005];//用邻接矩阵表示的图
int book[1005];//已确定的节点集合
int dis[1005];//最短路径
int num=0;//节点的总个数

int prim(int s) {
    int pos, min;//pos记录每次确定下来要加入集合book的那个节点,min表示当前这轮确定的最短路径
    int MST = 0;//累加最短路径,表示最短路径和

    book[s] = 1;//首先,将节点s放入集合book
    pos = s;

    for (int i = 1; i <= num; i++) //初始化dis
        dis[i] = edge[pos][i];

    //执行n-1次
    for (int i = 2; i <= num; i++) {
        min = INT_MAX;

        for (int j = 1; j <= num; j++) {
            if (book[j]==0 && min > dis[j]) {
                min = dis[j];
                pos = j;
            }
        }
        book[pos] = 1;//确定选择出离当前节点最近的那个节点
        MST += min;//加上这条最短路径

        for (int j = 1; j <= num; j++) //尝试更新dis
        if (book[j]==0 && dis[j] > edge[pos][j])//更新条件:j点未访问,加入新点后已访问集合到j的距离变小了
            dis[j] = edge[pos][j];
    }
    return MST;
}

int main() {
    int n;
    int i,j;
    while(cin>>n) {
        for(int i=1;i<=n;i++) {
            book[i]=0;
            dis[i]=0;
            for(int j=1;j<=n;j++) {
                edge[i][j]=0;
            }
        }

        num=n;
        for(i=1;i<=n;i++)//输入邻接矩阵(图)
            for(j=1;j<=n;j++)
                cin>>edge[i][j];
        int ans = prim(1);
        cout << ans << endl;    

    }

    return 0
 }

它的时间复杂度为O(n^2)
有一种优化的算法,就是Prim+堆。时间复杂度可以优化为O(n log n)
具体代码如下:

int dist(MAXN)
struct node
{
    int u,w;
    node(){}
    node(int u,int w):u(u),w(w){}
    friend bool operator<(node a,node b)
    {
        return a.w>b.w;
    }
 } 
 priority_queue<node> q;
 void prim(int s)
 {
    q.push(node);
    while (!q.empty())
     {
        node u=q.top;
        q.pop();
        flag[u.u]=1;
        for (int i=0;i<e[u.u].size();i++)
        {
            int v=e[u.u][i].v;
            int w=w[u.u][i].w;
            if (dist[v]>e[i].w)
            {
                dist[v]=w;
                if (!flag[v])
                {
                    q.push(node(v,dist[v]));
                 }
             }
         }
      } 
 }

算法证明:
• 图p是一个连通图,Y是对p使用prim算法得到的一棵生成树,Y1是p的一棵最小生成树
• 1.若Y=Y1,显然prim算法是正确的
• 2.若Y≠Y1,可进行如下推导:
• a)Y中有n(n≥1)条边不存在于Y1中,在构建Y的过程中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值