什么是图
图是右顶点和边组成。顶点表示对象,边表示两个对象的连接关系。
一般的表示方法:顶点集合是V、边的集合是E,图记做G=(V , E), 连接两点u和v的边记做e=(u,v)。
图的种类
图一般分为两种:
- 无向图
- 有向图
无向图
相邻:两个顶点之间有边。
路径:相邻顶点序列称为路径。
圈:起点和终点重合的路径称为圈。
连通图:任意两点之间都有路径连接的图叫做连通图。
度:顶点连接的边数叫做这个顶点的度。
树:没有圈的连通图叫做树。
森林:没有圈的非连通图叫做森林。
树的重要性质:一棵树的边数恰好是顶点数-1;反之,边数等于顶点数-1的连通图就是一颗树。
有向图
DAG:没有圈的有向图叫做DAG。
拓扑序:对于每个顶点我们给它一个编号,第i号顶点叫做
。那么存在从顶点
到顶点
的边时就有i
图的表示
- 邻接矩阵
- 邻接表
邻接矩阵
近接矩阵用|V| × |V|的二维数组来表示图。g[i][j]表示顶点i和顶点j的关系。
邻接表
用邻接矩阵表示稀疏图会浪费大量的内存空间。在邻接表中,是通过把从一个顶点出发与它相邻的所有节点用链表保存起来。所以只需要O(|V|+|E|)的内存空间。
邻接表的存储方法:
可以使用vector数组实现,比如: vector <int> G[MAX_N];
G[0]表示0号节点,该容器中的节点都是0号节点的邻接节点。G[1]表示1号节点,该容器中的所以节点都是1号节点的邻接节点。
总结:稀疏图用邻接表,稠密图用近接矩阵。
图的搜索
尝试用图的知识来解题
问题:二分图判定
给定一个具有n个顶点的图。要给图上的每个顶点染色,并且要使相邻顶点的颜色不同。问题是能否用最多两种颜色来染色?题目保证没有重边和自环。
限制条件
输入样例:
n=3; //表示顶点数
0 1 2 -1 //第一个数字表示顶点号,最后一个表示换行标志,中间表示该顶点的邻接点
1 0 2 -1
2 1 0 -1
该图形为:
输出样例:
No;
相邻顶点染成 不同颜色的问题叫做图的着色问题。对图进行染色所需要的最小颜色称为最小着色数。最小着色数2的图称为二分图。
如果只有两种颜色,那么确定一种颜色之后,和它相邻的顶点的颜色就确定了。因此选择任意一个顶点出发,依次给相邻顶点着色,就可以判断是否被两种颜色染色了。使用深度优先搜索(DFS)可以简单实现。
#include <iostream>
#include <vector>
#define MAX_V 1000
using namespace std;
vector<int> G[MAX_V]; //存储图,使用vector表结构
int V;//顶点数
int color[MAX_V] {}; //顶点颜色
void init(){
cin>>V;
int vec;
for(int i=0;i<V;i++){
cin>>vec;
while(true){
int temp;
cin>>temp;
if(temp == -1){
break;
}
G[vec].push_back(temp);
}
}
}
bool dfs(int v,int c){
color[v]=c;//顶点v染成c颜色
for(int i=0;i<G[v].size();i++){
if(color[G[v][i]]==c) return false; //如果邻接点被染成了c则返回false
if(color[G[v][i]]==0){ //如果邻接点被没有染色,则染色成-c.
if(!dfs(G[v][i],-c)){
return false;
}
}
}
return true;
}
void solve(){
for(int i=0;i<V;i++){
if(color[i]==0){
if(!dfs(i,1)) {
cout<<"No\n";
return;
}
}
}
cout<< "Yes\n";
}
int main(){
init();
solve();
return 0;
}
/*输入示例
4
0 1 3 -1
1 0 2 -1
2 1 3 -1
3 0 2 -1
*/