图
图的定义:图是由顶点的有穷非空集合和顶点之间的边的集合组成通常表示为G=(V,E);其中G表示一个图,V是图G中顶点的集合,E是图G中顶点之间的边的集合。
有向图
:任意两点之间的边都是有向边(有向边是指,<vi,vj>序偶vi表示弧尾,vj表示弧头,只能从i指向j)
无向图:任意两点之间的边都是无向边(即i,j两点之间的边没有方向可以互达)
简单图:
不存在自环
邻接:
无向图中任意两个点i,j若这两个点之间存在边(i,j)则称这两个点互为邻接点
依附:
有向图中对于任意两个vi,vj若存在弧<vi,vj>则称顶点vi邻接到vj,vj邻接自vi同时称弧<vi,vj>依附于顶点vj,vj。
稠密、稀疏图:
边数很少的图称为稀疏图,反之称为稠密图,概念很模糊一般靠相面!
顶点的度:
在无向图中,顶点v的度是指依附于该顶点的边数,通常记为TD (v)。
顶点的入度:
在有向图中,顶点v的入度是指以该顶点为弧头的弧的数目,记为ID (v);
顶点的出度:
在有向图中,顶点v的出度是指以该顶点为弧尾的弧的数目,记为OD (v)。
权:是指对边赋予的有意义的数值量。
网:边上带权的图,也称网图。
路径:在无向图G=(V, E)中,从顶点vp到顶点vq之间的路径是一个顶点序列(vp=vi0,vi1,vi2, …, vim=vq),其中,(vij-1,vij)∈E(1≤j≤m)。若G是有向图,则路径也是有方向的,顶点序列满足<vij-1,vij>∈E。
路径长度:(1)非带权图——路径上边的个数;(2)带权图——路径上各边的权之和。
回路(环):第一个顶点和最后一个顶点相同的路径。
**简单路径:**序列中顶点不重复出现的路径。
**简单回路(简单环):**除了第一个顶点和最后一个顶点外,其余顶点不重复出现的回路。
子图:若图G=(V,E),G’=(V’,E’),如果V’V 且E’ E ,则称图G’是G的子图。
连通图:在无向图中,如果从一个顶点vi到另一个顶点vj(i≠j)有路径,则称顶点vi和vj是连通的。如果图中任意两个顶点都是连通的,则称该图是连通图。
连通分量:非连通图的极大连通子图称为连通分量。 (1.含有极大顶点数; 2. 依附于这些顶点的所有边。)
强连通图:在有向图中,对图中任意一对顶点vi和vj (i≠j),若从顶点vi到顶点vj和从顶点vj到顶点vi均有路径,则称该有向图是强连通图。
强连通分量:非强连通图的极大强连通子图。
生成树:n个顶点的连通图G的生成树是包含G中全部顶点的一个极小连通子图。 (含有n-1条边,多——构成回路,少——不连通)
生成森林:在非连通图中,由每个连通分量都可以得到一棵生成树,这些连通分量的生成树就组成了一个非连通图的生成森林。
图的遍历
深度优先遍历:先从一个点开始从这个点未被访问的一个邻接点进行深度优先遍历到底了就返回直到这个点的所有邻接点都被访问然后返回上一层。
广度优先遍历:类似树的层序遍历首先把顶点入队然后把顶点的所有未访问的邻接点入队然后依次出队访问后续节点。
prim
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int Head[10000],Next[10000],ver[10000],po[10000],tot=0;
void inti(){
tot=0;
memset(Head,-1,sizeof(Head));
}
void add(int x,int y,int z){
tot++;
Next[tot]=Head[x];
Head[x]=tot;
ver[tot]=z;
po[tot]=y;
}
int lowcost[1000],adjvege[1000];
int main(){
int n,m,e,a[100][100];
while(cin>>n>>e){
inti();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
if(a[i][j]>0&&a[i][j]<100){
add(i,j,a[i][j]);
}
}
}
memset(lowcost,0x3f3f3f3f,sizeof(lowcost));
for(int i=1;i<=n;i++){
adjvege[i]=1;
if(a[1][i]>0&&a[1][i]<100)
lowcost[i]=a[1][i];
}
lowcost[1]=0;
int k=n-1;
while(k--){
int maxx=0x3f3f3f3f,pos;
for(int i=1;i<=n;i++){
if(lowcost[i]>0&&lowcost[i]<maxx)
{
maxx=lowcost[i];
pos=i;
}
}
cout<<lowcost[pos]<<' ';
lowcost[pos]=0;
for(int i=Head[pos];i!=-1;i=Next[i]){
int y=po[i],z=ver[i];
if(lowcost[y]>z){
lowcost[y]=z;
adjvege[y]=pos;
}
}
}
}
return 0;
}
Kruskal算法
选n-1条最短边并且这些边不能够成环,所以先按照边权大小排序从前到后选够n-1条边每次选边的时候通过并查集判断这个边加入之后是否会构成回路。
#include <stdio.h>
#include <iostream>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
typedef long long LL;
using namespace std;
typedef long long ll;
int bi[10000],a[1000][1000];
bool v[1000][1000];
int Find(int x){
int y=x;
while(bi[y]!=y)
y=bi[y];
return y;
}
int main()
{
int n,m;
while(cin>>n>>m){
memset(v,false,sizeof(v));
for(int i=1;i<=n;i++){
bi[i]=i;
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
}
int p=n-1;
while(p){
p--;
int x,y,maxx=0x3f3f3f3f;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(!v[i][j]&&Find(i)!=Find(j)&&a[i][j]<maxx&&a[i][j]<100){
maxx=a[i][j];
x=i,y=j;
//cout<<maxx<<endl;
}
}
}
cout<<x<<' '<<y<<' ';
v[x][y]=1;
bi[Find(y)]=Find(x);
}
cout<<endl;
}
}