图论 一、什么是图 1、图是(vertex,node顶点和 边(edge)组成。 2、分类 (1)无向图(无指向) 例如:亲属关系,路程图 (2)有向图(边有指向) 例如:流程图 (3)带权图(边上带权值) 权值可表示时间、价值等 ———无向图 1、如果两顶点之间有边连接,那么视两顶点相邻,相邻结点的序列称为路径。起点和终点重合的称为圈。任意两点都有路径连接,称为连通。顶点连接的边数称为顶点的度。 2、没有圈的连通图称为树, ———有向图 1、以顶点为起点的边的集合的大小称为顶点的入度,为终点的大小为出度。没有圈的有向图称为DAG。 二、图的表示 1、邻接矩阵 把边和结点用具体的数据结构保存下来,主要有邻接矩阵和邻接表。 使用二维数组来表示,个g[i][j]来表示顶点i和j关系。如果i和j连接值就为1,否则为0.无向图g[i][j]=g[j][i],有向图只需标注g[i][j].带权值使g[i][j]值为权值,0仍为权值,无连接为INF。 2、邻接表 表示从顶点到其他点边数集合 例:g[v].push_back(e)//顶点v,其他顶点e。 3、点多边比较稀疏的时候使用邻接表,但实现复杂,并且不易遍历。 三、图的搜索 主要通过DFS实现 例题: 给定一个具有n个顶点的图,相连的两顶点不同色,是否能实现?
#include <iostream> #define MAX 1000 int Graph[MAX][MAX];//存储图的序号 int color[MAX];//存储各个顶点的颜色 1或-1 using namespace std; int dfs(int point,int c)//把点point染成c色,并且从顶点point开始深度搜索,如果不满足就返回0 { color[point] = c; int i; for(i = 1;i <= Graph[point][0];i++) //对每一个相邻顶点判断 { // 如果相邻顶点的颜色相同,则返回0 if(color[Graph[point][i]] == c) return 0; // 如果相邻顶点还没有染色,则染成-c,并深度搜索判断真假 if(color[Graph[point][i]] == 0 && !dfs(Graph[point][i],-c)) return 0; } //如果所有顶点都满足,就返回1 return 1; } int main(void) { int N,i,j,flag = 1; // N是图顶点个数 cin>>N; for(i = 0;i < N;i++){ cin>>Graph[i][0]; //用Graph[i][0]来存储相邻顶点个数 for(j = 1;j <= Graph[i][0];j++){ cin>>Graph[i][j]; } } //读取图 for(i = 0;i < N;i++){ if(color[i] == 0) //如果点i还没有染色,就染成1 { if(!dfs(i,1)){ //如果判断为假,则退出 cout<<"NO"; flag = 0; break; } } } if(flag == 1) //如果判断为真,则输出YES cout<<"YES"; return 0; }四、最短路径 1、单源最短路径问题。 固定起点求他到其他点最短路径。d[v]表示起点到V顶点距离。 实现代码
#include <iostream> #define MAX_E 1000 #define INF 1e9 using namespace std; struct edge{int from,int to,int cost}; edge es[MAX_E];//边的集合 int d[MAX_E];//最短距离 int v,e;//顶点和边 void shortpath(int s)//s为起点 { for(int i=0;i<v;i++) d[i]=INF; d[s]=0; while(true)// { bool update=false; for(int i=0;i<e;i++)//遍历所有边 { egde e=es[i]; if(d.[e.from]!=INF&&d[e.to]>d[e.from]+e.cost)) { d[e.to]=d[e.from]+e.cost; update=true; } } if(!uopdate) break;//不再能更新,找出所有起点到其他顶点最短路径。 } }最近总结 今天还是跟着做了一场比赛,一如既往的糟糕,心态快炸了,做到3个小时的时候,提交六个题,只上传成功一个,其他全部pending,当时快感觉做不下去了,看了榜单,QAQ。队友打气最后还是硬着头皮做了。题目的思维题,总是搞错,总想着暴力枚举,递归出奇迹,下次一定要多读题,多思考。