题外话
这篇是我的第一篇博客,希望得到大家的支持。
定义
图(graph)是由两个集合构成,一个是非空但有限的集合V,另一个描述了顶点之间的关系。边的集合为E。
顶点:图中结点称为顶点,第i个顶点记为vi。
边:两个顶点vi和vj相关联称作顶点vi和顶点vj之间有一条边。
有向图和无向图
有向图:有箭头,有方向;
无向图:没有箭头,双向都可。
举两个例子:
比如这张G1,它没有方向,没有箭头,就是无向图。
再比如这张G2,它有方向,有箭头,就是有向图。
对,就是那么简单。
图的读入
这里介绍一种最简单的读入方法。
图主要分两个集合读入:点和边。
先来看点:
点的定义可以有一个变量vertex来表示,就像这样:
const int vertex=10;//点的数量为10
接下来看边的数量:
首先要知道一个公式:
设点的数量为n,则无向图内:边的数量edge=n(n-1),有向图还需在此基础上/2。
那么我们可以得出:(此处为无向图)
const int edge=vertex*(vertex-1);
接下来,我们还需要两个集合来表示点和边的集合。
点的集合可以用一维数组来储存它们的值。
定义v[i]=j表示第i个节点编号是j,得:
int v[vertex];//点的集合
边的集合
边需要有三个值:左顶点、右顶点、长度。
那么可以简单得知,使用结构体数组struct即可,就像这样:
struct edges
{
int from;//该条边的左顶点
int to;//该条边的右顶点
double w;//边的长度
};
edges e[edge+1];//边集合数组
存储的变量弄完了,接下来要解决如何输入加边的问题了。
为了美观和方便,我们可以使用一个void函数,其中形式参数为起点、终点和长度。
void add(int u/*起点*/,int v/*终点*/,int w/*长度*/)
函数内部的边的数据切换可以定义一个cnt作为当前在读入的边,初始化赋值为1,之后cnt++进行切换即可。中间再调用结构体数组三个变量进行赋值即可。
void add(int u/*起点*/,int v/*终点*/,int w/*长度*/){
e[cnt].from=u;//记录第cnt条边的左顶点是u
e[cnt].to=v;//记录第cnt条边的右顶点是v
e[cnt].w=w;//记录第cnt条边的长度
cnt++;//换下一条边去读
}
最后,主函数内再用for循环进行输入和调用函数就能够完成输入了。
for(int i=1;i<=5;i++)//读入
{
int u,v,w;//左顶点 右顶点 长度
cin>>u>>v>>w;
add(u,v,w);//单向只需这个
add(v,u,w);//双向
}
如果想要检查输入是否正确,再加一个for循环进行输出即可。
for(int i=1;i<=5;i++)
{
printf("e[%d].from=%d,e[%d].to=%d",i,e[i].from,i,e[i].to);
}
是不是理解上很简单?
最后,献上完整的读入与输出图的代码:
完整代码
#include<bits/stdc++.h>
using namespace std;
//图的储存
//点集合 边集合
const int vertex=10;//点的数量
const int edge=vertex*(vertex-1);//边的数量 有向就/2
int v[vertex];//点集合 v[i]=j表示第i个节点编号是j
struct edges//边
{
int from;//该条边的左顶点
int to;//该条边的右顶点
double w;//边的长度
};
edges e[edge+1];//边集合
int cnt=1;//当前在读入第cnt条边
void add(int u/*起点*/,int v/*终点*/,int w/*长度*/){
e[cnt].from=u;//记录第cnt条边的左顶点是u
e[cnt].to=v;//记录第cnt条边的右顶点是v
e[cnt].w=w;//记录第cnt条边的长度
cnt++;//换下一条边去读
}
int main()
{
for(int i=1;i<=5;i++)//读入
{
int u,v,w;// 左顶点 右顶点 长度
cin>>u>>v>>w;
add(u,v,w);//单向只需这个
add(v,u,w);//双向
}
for(int i=1;i<=5;i++)
{
printf("e[%d].from=%d,e[%d].to=%d",i,e[i].from,i,e[i].to);
}
}