基础图论--存图

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

有空整理一下下

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

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)就好了 耶  操作也相对简单,某些题很适用

前向星---记录下每个起始点的第一条边,先按点同时按边遍历,需要排序, 详见代码

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;
        }
    }
}
View Code

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

//链式前向星
/*
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\n", u, edge[i].to, edge[i].w);
    }
}
View Code

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

猜你喜欢

转载自www.cnblogs.com/op-z/p/10804068.html