图的存边

在图论中,最基本的应该就是建边了

1.邻接矩阵

最简单,最直接的办法,就是整一个二维数组 f[10000][10000]
f[i][j]=w 表示从i点到j点有一条权值为w的边,如果没有权值,可以赋值为1,0来区别是否油边
代码大概长成这样:

const int N=1e4+10;
int f[N][N];
void add(int u,int v,int w){
	f[u][v]=w;
}
int main(){
    int m;
    scanf("%d",&m);
    while(m--){
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        void(x,y,w);
    }
}

优势:稠密图中表现仍然良好
劣势:二维数组能开的数量有限,对于m>1e4的数据束手无策

2.邻接表:

上面的图的问题在于空间的问题,那我们就借此观察如何优化
我们发现,上面的二维数组我们可以转化成链表,用链表存图

此时我们可以用结构体来存边

struct edge{
    int to,nxt,w;
}e[N];
int head[N];

image
就说这个图吧,我们思考如何用链表实现边与边的连通
为了方便,我们用vector来存邻接表
核心思想的话就是存储每个顶点能够到达哪些顶点。

vector<edge> e[MAXN];
inline void add(int from, int to, int w){
    edge e={to, w};
    edges[from].push_back(e);  //向vector的最后添加一条边
}
遍历图时用通常遍历数组的方法即可

但是考虑到vector常数大的问题,我们此时还是直接用数组

int cnt=0;
void add(int u,int v,int w){//边的起始点,终点,权值
	e[++cnt].to=v;
	e[cnt].val=w;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}

如果想遍历这个点和哪些能到达的距离为1的点的话

for(int i=head[u];i;i=e[i].nxt){
	/*此时的e[i].to指的是点u的下一个节点的id,e[i].val指的是到v的长度*/
}

3.链式前向星(一般都用这个)

这种做法是用数组模拟链表
As we all know:STL’s 常数 is very 的大
所以这个存图方式算是比上一个又优化了不少(其实可以数组模拟链表,但是据某位@Locura大佬所说:“正经人谁写链表啊!!!”)
核心代码如下:

#include<iostream>
using namespace std;
const int N=1e5+10;
int n,cnt;
struct node{
    int w,to,nxt;
}e[N];
int head[N];
void add(int u,int v,int w){
    e[++cnt].to=v;
    e[cnt].w=w;
    e[cnt].nxt=head[u];
    head[u]=cnt;
}
int main(){
    scanf("%d",&n);//添加几条边
    while(n--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);//添加一条以a为起点,b为终点,权值为c的边
    }
    cout<<endl;
    for(int start=1;start<=6;start++){
        for(int i=head[start];i;i=e[i].nxt) cout<<start<<" "<<e[i].to<<" "<<e[i].w<<endl;
    }
    return 0;   
}
/*
5
1 3 5
2 4 5
4 3 6
6 1 4
1 4 3
*/
posted @ 2021-08-25 21:58  RevolutionBP  阅读(83)  评论(0编辑  收藏  举报