在计算机中存储数据结构——图,通常有两种方法。
一、邻接矩阵
定义二位数组map[n][m],其中任意一个元素map[i][j]表示:由i出发到j的一条边。对于无权图,map[i][j]=1表示i到j有边, map[i][j]=0表示i到j无边;对于有权图来说,map[i][j]=x表示i到j有边权为x的边,map[i][j]= ∞。对于无向图,map[i][j]=map[j][i],相当于正反两条边,此时矩阵斜向对称。
在知道端点的情况下查边快,但费内存,适用于点少的稠密图,可以用于oi中的简单算法。
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int u, v, w;
int map[1000][1000];//邻接矩阵定义
void addedge(int u, int v, int w)//邻接矩阵加边
{
map[u][v] = w;
}
int n, m;//n为点数,m为边数
int main()
{
memset(map, 0x3f3f3f3f,sizeof(map));
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w);
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
printf("%010d ", map[i][j]);
}
printf("\n");
}
return 0;
}
二、前向星与链式前向星
(1)前向星(几乎无用的算法,只为了链式前向星做铺垫)
edge类型的结构体e[i]数组:用于记录边的节点和权重信息。
head[i]数组:用于标记以第i个节点为起点在e数组中第一次出现的位置。
struct edge
{
int u;//边的起点
int v;//边的终点
int w;//边的权值
};
edge e[10000];//边,i无实际意义,可以理解为边的编
比如说我们有边:
1,2,3
3,4,5
2,3,4
4,5,6
假设为无向图,double一下:
1,2,3
2,1,3
3,4,5
4,3,5
2,3,4
3,2,4
4,5,6
5,4,6
然后用sort二级排序,先按u从小到大排序,u相同的情况下再按v从小到大排序
1,2,3
2,1,3
2,3,4
3,2,4
3,4,5
4,3,5
4,5,6
5,4,6
代码:
#include <cstdio>
#include <iostream>
#include<algorithm>
using namespace std;
struct edge
{
int u;//边的起点
int v;//边的终点
int w;//边的权值
};
edge e[10000];//边,i无实际意义,可以理解为边的编号
int n, m;//n为点数,m为边数
int head[1000];//以第i个节点为源头,所指出所有边的第一条边的编号
bool cmp(edge a, edge b)
{
if (a.u < b.u)
{
return true;
}
else if (a.u==b.u)
{
if (a.v < b.v)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d", &e[2 * i].u, &e[2 * i].v, &e[2 * i].w);
e[2 * i].u = e[2 * i - 1].u;e[2 * i].v = e[2 * i - 1].v;e[2 * i].w = e[2 * i - 1].w;
}
sort(e + 1, e + 2 * m + 1, cmp);
head[1] = 1;
for (int i = 2; i <= n; i++)
{
if (e[i - 1].u != e[i].u) { head[e[i].u] = i; }
}
return 0;
}
(2)链式前向星:懒得用前向星排序了,于是干脆不排了,弄个链表,快一点点,少了个nlogn。
struct edge
{
int v;//边的终点
int head;//连接同一个节点的上一条边的编号
int w;//边的权值
};
edge e[10000];//i可以理解为边的编号
int head[1000];//以第i个节点为源头,按输入顺序,所指出所有边的最后一条边的编号
代码:
#include <cstdio>
#include <iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct edge
{
int ve;//边的终点
int next;//连接同一个节点的上一条边的编号
int we;//边的权值
};
edge e[10000];//i可以理解为边的编号
int n, m;//n为点数,m为边数
int head[1000];//以第i个节点为源头,按输入顺序,所指出所有边的最后一条边的编号
int cnt;//计数器
void add(int u,int v,int w)//加边
{
e[cnt].ve = v;
e[cnt].we = w;
e[cnt].next = head[u];
head[u] = cnt++;
}
int main()
{
int u, v, w;
scanf("%d%d", &n, &m);
memset(head,-1, sizeof(head));//-1可以用memset赋值
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
return 0;
}