今天学习了代码源初级包图论的第一节课,图的基本概念及存储方式。
基本概念:
图
一个图是由点集 V V V和边集 E E E组成的,一般会记作为图 G = < V , E > G=<V,E> G=<V,E>,一条边连接两个顶点。
点集 V V V包含了所有顶点,边集 E E E包含了所有边,点集 V V V为空时称为空图。
全部由无向边构成的图称为无向图,由有向图构成的图称为有向图,有向边可以理解为单行道。
自环:边连接的两个点是同一个点。
重边:无向图中指在两点之间有多条边 ( ≥ 2 ) (\geq2) (≥2)连接,如果是有向图则是在两点之间有多条同方向的边 ( ≥ 2 ) (\geq2) (≥2)连接。
孤点:没有连接边的点。
简单图:没有自环和重边的图称为简单图。
度数
无向图的度数:对于无向图中的顶点 v v v, v v v作为边的端点的次数称为 v v v的度数,记为 d ( v ) d(v) d(v)。
有向图的度数:对于有向图的顶点 v v v, v v v作为边的起点的次数称为 v v v的出度,记为 d + ( v ) d^+(v) d+(v); v v v作为边的终点的次数称为 v v v的入度,记为 d − ( v ) d^-(v) d−(v);顶点 v v v的度数 d ( v ) = d + ( v ) + d − ( v ) d(v)=d^+(v)+d^-(v) d(v)=d+(v)+d−(v)。
每个图 G G G的最大度为所有顶点度数的最大值,记做 Δ ( G ) \Delta(G) Δ(G);最小度为所有顶点度数的最小值,记做 δ ( G ) \delta(G) δ(G)。
一张图的所有点的度数和为边数的两倍,有向图所有顶点的出度和等于入度和。
完全图和竞赛图
完全图(无向图):设 G G G为一个有 n n n个节点的无向简单图,若 G G G中每一个顶点都与其余 n − 1 n-1 n−1个顶点有边相连,则称 G G G为** n n n阶无向完全图**,简称为** n n n阶完全图**,记做 k n k_n kn,一共有 C n 2 C_n^2 Cn2条边。
完全图(有向图):设 G G G为一个有 n n n个节点的有向简单图,若 G G G中每个顶点都有连到其余 n − 1 n-1 n−1个顶点的边,且都有这些节点连向它的边,则称 G G G为** n n n阶有向完全图**,一共有 n ( n − 1 ) n(n-1) n(n−1)条边。
竞赛图:基于** n n n阶无向完全图**,给每条边任意一个方向形成的图称为** n n n阶竞赛图**。
子图、生成子图
子图:设 G = < V , E > , G ′ = < V ′ , E ′ > G=<V,E>,G^{'}=<V^{'},E^{'}> G=<V,E>,G′=<V′,E′>为两个图(同为无向图或者有向图),如果 V ′ ⊆ V V^{'}\subseteq V V′⊆V且 E ′ ⊆ E E^{'}\subseteq E E′⊆E,则称图 G ′ G^{'} G′为图 G G G的子图, G G G称为图 G ′ G^{'} G′的母图,记做 G ′ ⊆ G G^{'}\subseteq G G′⊆G。
如果 V ′ = V V^{'}=V V′=V,则称 G ′ G^{'} G′ 为 G G G的生成子图。
如果 V ′ ⊂ V V^{'}\sub V V′⊂V或者 E ′ ⊂ E E^{'}\sub E E′⊂E,则称 G ′ G^{'} G′ 为 G G G的真子图。
补图
补图:设 G = < V , E > G=<V,E> G=<V,E>是一个 n n n阶无向简单图,以 V V V为顶点集,以所有使 G G G成为完全图 K n K_n Kn需要添加的边的集合为边集的图,称为 G G G的补图,记做 G ˉ \bar{G} Gˉ。
简单来说:图和它的补图顶点集相同;边集的交集为空,并集是完全图的边集。
同构
同构定义:设 G G G和 G ′ G^{'} G′是分别具有顶点集 V V V和 V ′ V^{'} V′的两个图。如果存在一个双射 h : V → V ′ h:V\to V^{'} h:V→V′满足当且仅当 ( v i , v j ) (v_i,v_j) (vi,vj)是 G ′ G^{'} G′的边时, ( h ( v i ) , h ( v j ) ) (h(v_i),h(v_j)) (h(vi),h(vj))是 G ′ G^{'} G′的边,则称图 G G G和 G ′ G^{'} G′同构。
通路、回路、路径和距离
对于一个图 G G G, G G G中顶点与边的交替序列 v 0 e 1 v 1 e 2 v 2 e 3 v 3 … e n v n v_0e_1v_1e_2v_2e_3v_3\ldots e_nv_n v0e1v1e2v2e3v3…envn称为 v 0 v_0 v0到 v n v_n vn的通路,其中 v 0 , v n v_0,v_n v0,vn称为通路的起点和终点,通路中边的条数称为它的长度。在有向图中,要保持边的方向一致。
对于一条通路,如果 v 0 = v n v_0=v_n v0=vn,则称为回路。如果 v 0 = v n v_0=v_n v0=vn且其他所有顶点都不相同,则称为环。
如果通路中的所有边都不相同,称为迹。如果通路中的所有顶点都不相同,边也各不相同,则称为路径
图中连接两点之间最短的路径长度称为距离
连通性和连通块
无向图:
连通性:设无向图 G = < V , E > , u , v ∈ V G=<V,E>,u,v\in V G=<V,E>,u,v∈V,如果 u , v u,v u,v之间存在通路,则称 u , v u,v u,v是连通的。对于$\forall v\in V , , ,v和v$自己是连通的。
连通图:对于任意非空无向图 G G G,若 G G G中任意两个顶点都是连通的,则称 G G G为连通图。
连通块:对于无向图 G G G的一个连通子图 H H H,如果不存在 F F F满足 H ⊂ F ⊆ G H\sub F \subseteq G H⊂F⊆G且 F F F为连通图,则称 H H H是 G G G的一个连通块/连通分量, H H H是一个极大连通子图。
有向图:
连通性:设有向图 G = < V , E > , u , v ∈ V G=<V,E>,u,v\in V G=<V,E>,u,v∈V,如果 u , v u,v u,v之间存在通路,则称 u u u可达 v v v。如果 u , v u,v u,v相互可达,则称 u , v u,v u,v连通。
强联通:如果有向图 G G G中的顶点两两可达,可以定义有向图的强联通块/强连通分量。
强连通块:与无向图的类似,可以定义有向图的强联通块/强连通分量。
图的存储方式
邻接矩阵:a[x][y]
邻接表:vector<int> edge[N];
题目
简单图的判定:
代码如下:
/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl '\n' //交互题删掉
typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int N = 1010;
int a[N][N];
int n, m;
void solve()
{
cin >> n >> m;
bool ok = 1;
for (int i = 1; i <= m; i++)
{
int x, y;
cin >> x >> y;
if (x == y || a[x][y])
{
ok = 0;
}
a[x][y] = a[y][x] = 1;
}
if (!ok)
{
cout << "No" << endl;
}
else
{
cout << "Yes" << endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
t = 1;
while (t--)
{
solve();
}
return 0;
}
顶点度数统计:
代码如下:
/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl '\n' //交互题删掉
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int N = 1e3 + 10;
int n, m;
int din[N], dout[N];
void solve()
{
cin >> n >> m;
while (m--)
{
int a, b;
cin >> a >> b;
din[b]++;
dout[a]++;
}
for (int i = 1; i <= n; i++)
{
cout << din[i] + dout[i] << " \n"[i == n];
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
t = 1;
while (t--)
{
solve();
}
return 0;
}
顶点度数合法性:
/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl '\n' //交互题删掉
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
int n;
void solve()
{
cin >> n;
ll sum = 0;
for (int i = 1; i <= n; i++)
{
int a;
cin >> a;
sum += a;
}
if (sum & 1)
{
cout << "No" << endl;
}
else
{
cout << "Yes" << endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
t = 1;
while (t--)
{
solve();
}
return 0;
}