zoukankan      html  css  js  c++  java
  • 基础图论--存图

    图论蛮好玩的呢  比起数论真是有趣多了

    有空整理一下下

    首先,图是个什么鬼东东呢

    graph, 一堆点集,一堆边集,可以把各种事物抽象成点,事物之间的联系用边来表示,边上还可有权值,表示距离费用等

    e.g. 把各个城市抽象成点,城市之间可以由高铁直达的称作有联系(边), 边上还可附加权值,俩城市间距离等

    至于一些基本概念, 有向无向,是否成环,入度出度等就不多讲啦 基本概念理解就好

    现在看看存图,看不同情况来选适合的存图方式

    邻接矩阵---二维矩阵 a[ n ][ m ], 可用a[i][j]=1或0表示点i,j之间是否有边,缺点就是很占空间耶

    邻接表---可以用链表呢(详见数据结构与算法,一些算法中提及的优化呵呵呵, 缺点就是修改查询麻烦

    vector---归到邻接表啦,开个vector<ll>v[ N ], 点i,j有边,直接v[ i ].push_back(j)就好了 耶  操作也相对简单,某些题很适用

    按边存图(直接存边,有时比较方便

    typedef long long ll;
    struct node
    {
        ll u, v, w;
    }e[N];
    
    ll cnt;
    void add(ll u, ll v, ll w)
    {
        e[cnt].u=u;
        e[cnt].v=v;
        e[cnt].w=w;
        cnt++;
    }

    前向星---记录下每个起始点的第一条边,先按点同时按边遍历,需要排序, 详见代码(一般不用,直接用它的升级版——链式前向星

    struct node
    {
        int s, e, w;
    }edge[MAXN];//边集
    bool cmp(node a, node b)
    {
        if(a.s==b.s && a.e==b.e) return a.w<b.w;
        if(a.s==b.s) return a.e<b.e;
        return a.s<b.s;
    }
    int head[MAXN]; //存起点为i的第一条边的位置
    int main()
    {
        int n, m;
        int i, j, k;
        while(cin>>m>>n) //m点  n条边
        {
            for(i=0; i<n; i++)
                cin>>edge[i].s>>edge[i].e>>edge[i].w;
            sort(edge, edge+n, cmp);  //排序以边的起点非递减序排
            
            memset(head, -1, sizeof(head));
            head[edge[0].s]=0;
            for(i=1; i<n; i++)
                if(edge[i].s!=edge[i-1].s) //存起点为i的第一条边的位置
                head[edge[i].s]=i;
            
            for(i=1; i<=m; i++) //遍历各点  输出以该点为起始点的所有边
            {
                for(k=head[i]; edge[k].s==i && k<n; k++)
                    cout<<edge[k].s<<' '<<edge[k].e<<' '<<edge[k].w<<endl;
            }
        }
    }

    链式前向星---不需排序 ,很巧妙, 详见代码

    //链式前向星
    /*
    edge[0].to = 2;     edge[0].next = -1;      head[1] = 0;
    edge[1].to = 3;     edge[1].next = -1;      head[2] = 1;
    edge[2].to = 4;     edge[2],next = -1;      head[3] = 2;
    edge[3].to = 3;     edge[3].next = 0;       head[1] = 3;
    edge[4].to = 1;     edge[4].next = -1;      head[4] = 4;
    edge[5].to = 5;     edge[5].next = 3;       head[1] = 5;
    edge[6].to = 5;     edge[6].next = 4;       head[4] = 6;
    */
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<set>
    #include<string>
    using namespace std;
    const int INF=0x3f3f3f3f;
    typedef pair<int, int> p;
    typedef long long ll;
    #define fi first
    #define se second
    #define MAXN 10000+5
    #define NIL -1
    struct node
    {
        int next, to, w; //edge[i].to 存 第i条边 的终点 .next存与边i同起点的前一条边
    }edge[MAXN];
    int head[MAXN];//head[i] i为有边节点 head存该节点 边 的最大编号 存的是边
    int cnt;
    void add(int u,int v,int w)//起点 终点 权值
    {
        edge[cnt].w=w;
        edge[cnt].to=v;
        edge[cnt].next=head[u];
        head[u]=cnt++;
    }
    int main()
    {
        int n, m;
        int i, j, k;
        int u, v, w;
        while(~scanf("%d%d", &n, &m)&& n && m) //n节点个数 m输入次数 一个节点可能有多条边
        {
            memset(head, -1, sizeof(head));
            cnt=0;
            for(i=0; i<m; i++)
            {
                scanf("%d%d%d", &u, &v, &w);
                add(u, v, w);
            }
            for(u = 1; u<=n; u++)
               for(i=head[u]; ~i; i=edge[i].next)//逆序遍历 i为边
                     printf("(%d %d)--> %d
    ", u, edge[i].to, edge[i].w);
        }
    }

    感觉用链式前向星比较顺手,看具体题目要求再选了

  • 相关阅读:
    C++内存管理
    多线程和多进程的区别(C++)
    如何用C语言封装 C++的类,在 C里面使用
    C/C++将一个整型数组拼接成一个字符串
    C代码中如何调用C++ C++中如何调用C
    Application对象的使用-数据传递以及内存泄漏
    《鸟哥的Linux私房菜》读书笔记二
    《鸟哥的Linux私房菜》读书笔记一
    greenDaoMaster的学习研究
    Handler 引起的内存泄露
  • 原文地址:https://www.cnblogs.com/op-z/p/10804068.html
Copyright © 2011-2022 走看看