图的总结
思维导图
重要概念
1.假设图中有n个顶点,e条边,则 含有 e=n(n-1)/2条边的无向图称作完全图; 含有 e=n(n-1)条弧的有向图称作有向完全图; 若边或弧的个数 e<nlogn,则称作稀疏图,否则称 作稠密图。
2.假若顶点v和顶点w之间存在一条边,则称顶点v和w互为邻接点; 边(v,w)和顶点v和w相关联;和顶点v 关联的边的数目定义为边的度。
3.对有向图来说, 顶点的出度: 以顶点v为弧尾的 弧的数目; 顶点的入度: 以顶点v为弧头的 弧的数目。 顶点的度(TD)=出度(OD)+入度(ID) 。
4.简单路径:序列中顶点不重复出现 的路径。 简单回路:序列中第一个顶点和最后 一个顶点相同的路径。若图G中任意两个顶点之间都有路径相通,则称 此图为连通图;若无向图为非连通图,则图中各个极大连通子图 称作此图的连通分量。若无向图为非连通图,则图中各个极大连通子图 称作此图的连通分量。对有向图来说,若任意两个顶点之间都存在一条有向路径,则称此 有向图为强连通图。否则,其各个强连通子图称作它的强连通分量。
5.邻接矩阵建图与深度遍历和广度遍历
void CreateMGraph(MGraph& g, int n, int e)//建图
{
g.n = n;
g.e = e;
int i, j;
for (i = 1; i < g.n+1; i++) {
for (j = 1; j < g.n+1; j++) {
g.edges[i][j] = 0;
}
}
int a, b;
for (i = 0; i < g.e; i++) {
cin >> a >> b;
g.edges[a][b] = 1;
g.edges[b][a] = 1;
}
}
void DFS(MGraph g, int v)//深度遍历
{
visited[v] = 1;
flag++;
if (flag != g.n) {
cout << v << " ";
}
else {
cout << v;
}
for (int i = 1; i < g.n+1; ++i) {
if (g.edges[v][i] != 0 && visited[i] == 0) {
DFS(g, i);
}
}
}
void BFS(MGraph g, int v)//广度遍历
{
int Q[MAXV];
int f = 0, r = 0;
int u, w;
flag += 1;
cout << v << " ";
visited[v] = 1;
Q[r++] = v;
while (r != g.n)
{
u = Q[f++];
for (w = 1; w < g.n+1; w++)
{
if (g.edges[u][w] != 0 && visited[w] == 0)
{
flag++;
if (flag != 2 * g.n) {
cout << w << " ";
}
else {
cout << w;
}
visited[w] = 1;
Q[r++] = w;
}
}
}
}
6.邻接表建图与深度遍历和广度遍历
void CreateAdj(AdjGraph*& G, int n, int e)//创建图邻接表
{
int i;
G = new AdjGraph;
for (i = 1; i <= n; i++) {
G->adjlist[i].data = i;
G->adjlist[i].firstarc = NULL;
}
int a, b;
for (i = 0; i < e; i++) {
cin >> a >> b;
ArcNode* p = new ArcNode;
p->adjvex = b;
p->nextarc = G->adjlist[a].firstarc;
G->adjlist[a].firstarc = p;
ArcNode* q = new ArcNode;
q->adjvex = a;
q->nextarc = G->adjlist[b].firstarc;
G->adjlist[b].firstarc = q;
}
G->n = n;
G->e = e;
}
void DFS(AdjGraph* G, int v)//v节点开始深度遍历
{
visited[v] = 1;
flag++;
if (flag != G->n) {
cout << v << " ";
}
else {
cout << v;
}
ArcNode* p;
p = G->adjlist[v].firstarc;
while (p != NULL) {
if (visited[p->adjvex] == 0) {
DFS(G, p->adjvex);
}
p = p->nextarc;
}
}
void BFS(AdjGraph* G, int v)//v节点开始广度遍历
{
int Q[MAXV];
int f = 0, r = 0;
int u, w;
flag += 1;
cout << v << " ";
visited[v] = 1;
Q[r++] = v;
ArcNode* p = new ArcNode;
p = G->adjlist[v].firstarc;
while (r != G->n)
{
u = Q[f++];
p = G->adjlist[u].firstarc;
while (p != NULL) {
int n = p->adjvex;
if (visited[n] == 0) {
flag++;
if (flag != 2 * G->n) {
cout << n << " ";
}
else {
cout << n;
}
visited[n] = 1;
Q[r++] = n;
}
p = p->nextarc;
}
}
}
疑难问题及解决方案
公路村村通
题目意思概括:建立一个公路图,村与村之间道路成本,建立一张带权图,并找到将每个村子连起来的路的最小成本,意思就是求最小生成是,用Prim算法来实现。
#include <iostream>
using namespace std;
#include <stdlib.h>
#define INF 0x7fffffff
#define maxn 1001
typedef struct _gra {
int n, e;
int data[maxn][maxn];
}gra;
void prim(gra* g, int v);
int main()
{
gra* g = (gra*)malloc(sizeof(gra));
for (int i = 0; i < maxn; i++)
for (int j = 0; j < maxn; j++) {
if (i == j)
g->data[i][j] = 0;
else g->data[i][j] = INF;
}
int n, m, k, p, c;
cin >> n >> m;
g->n = n;
g->e = m;
for (int i = 0; i < m; i++) {
cin >> k >> p >> c;
g->data[k][p] = g->data[p][k] = c;
}
if (m < n - 1)printf("-1");
else
prim(g, 1);
return 0;
}
void prim(gra* g, int v) {
int sum = 0;
int lowcost[maxn];
int close[maxn];
for (int i = 1; i <= g->n; i++) {
lowcost[i] = g->data[v][i];
close[i] = v;
}
lowcost[v] = 0;
for (int i = 2; i <= g->n; i++) {
int min = INF, k = 0;
for (int j = 1; j <= g->n; j++) {
if (lowcost[j] < min && lowcost[j] != 0) {
min = lowcost[j];
k = j;
}
}
sum += lowcost[k];
lowcost[k] = 0;
for (int j = 1; j <= g->n; j++) {
if (lowcost[j] != 0 && g->data[k][j] < lowcost[j]) {
lowcost[j] = g->data[k][j];
close[j] = k;
}
}
}
int flag = 0;
for (int i = 1; i <= g->n; i++) {
if (lowcost[i] == INF) {
flag = 1;
break;
}
}
if (flag)cout << "-1";
else cout << sum;
}