存储结构
//图的二维数组邻接矩阵存储 int n,e,w; //定点数和边数 权值 int g[101][101]; void make1(){ cin>>n; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j=+) g[i][j]=0x7fffffff; } //初始化 cin>>e; int x,y; for(int i=1;i<=e;i++) { cin>>x>>y>>w; g[x][y]=w; g[y][x]=w; //这是由于无向图,所以有两句 } } //邻接表 struct node{ int from,to,dis; node(int a,int b,int c){ from=a;to=b;dis=c; } }; vector<node> adj[maxn]; //数组模拟邻接表 //专业名------链式前向星 struct Edge{ int next; //下一条编的编号 int to; //这条边的去处 int dis; //边的权值 }edge[1001]; //这是边 int head[101],num_edge; //这是节点 void add_edge(int from,int to,int dis){ //添加一条从from到to的距离为dis的单向边! edge[num_edge].to=to; edge[num_edge].dis=dis; edge[++num_edge].next=head[from]; head[from]=num_edge; } void make2(){ cin>>n>>e; num_edge=0; int x,y,d; for(int i=1;i<=e;i++){ cin>>x>>y>>d; add_edge(x,y,d); } for(int i=head[1];i!=0;i=edge[i].next){ //遍历操作 } } int main(){ return 0; }
图的遍历
BFS、DFS
重要概念:
深度优先生成树
回退边
void dfss(int x,int depht){ //带层数的(邻接表版) vis[x]=1; for(int i=1;i<=adj[x].size();i++){ int j=adj[x][i]; if(vis[j]) dfs(j,depth+1); //不需要判断是不是连接 } } //广度优先 struct node{ int v; //顶点编号 int layer; //层号 }; vector<node> ajd[MAXN]; void bfsss(int x,int layer){ node start; start.v=x; //起始编号 start.layer=0; queue<node> q; q.push(start); vis[x]=1; while(!q.empty()){ node now=q.front(); q.pop(); int u=now.v; for(int i=1;i<ajd[u].size();i++){ node j=adj[u][i]; //相连的顶点 j.layer=now.layer+1; if(vis[j.v]==0){ q.push(j); vis[j.v]=1; } } } } //对整张图进行遍历 //如果图是联通的,那么只需要进行一次遍历了 void travdfs(){ for(int i=1;i<=n;i++){ if(vis[i]==0) dfs(i); } } void travbfs(){ for(int i=1;i<=n;i++){ if(vis[i]==0) bfs(i,1); //层数 }
例:欧拉路(一笔画问题)、欧拉回路
从图中某个点出发遍历整个图,每条边通过且通过一次。
一、是否存在欧拉路或欧拉回路
(1)图应该是联通图:DFS或并查集
(2)无向图:全部都是偶点:存在欧拉回路
有两个奇点:存在欧拉路,一个为起点,一个为终点
(3)有向图:每个点的出度标记为1,入度标记为-1,出度+入度即为度数,
有向图存在欧拉回路:只有1个度为1(起点),1个度为-1(终点),其他都为0
二、输出欧拉回路:
递归DFS,在后面打印或记录,但是如果数据很大,就得采用非递归形式。
三、混合图欧拉回路问题:最大流
http://ybt.ssoier.cn:8088/problem_show.php?pid=1341
int n,e; int circuit[101],d[101][101],c[101]; //c是每个点的度,用来判断是欧拉路还是欧拉回路 int num; void find(int i){ for(int j=1;j<=n;j++){ if(d[i][j]==1){ d[i][j]=d[j][i]=0; //删除这条边 find(j); } } circuit[++num]=i; //记录路径 } //这是欧拉路(2个奇点),欧拉回路(0个奇点) int main(){ cin>>n>>e; int x,y; memset(c,0,sizeof(c)); memset(d,0,sizeof(d)); for(int i=1;i<=e;i++){ cin>>x>>y; d[x][y]=d[y][x]=1; c[x]++; c[y]++; } int start=1; for(int i=1;i<=n;i++){ if(c[i]%2==1) start=i; //从奇点开始 } num=0; find(start); for(int i=1;i<=num;i++) cout<<circuit[i]<<" "; cout<<endl; return 0; }
哈密尔顿环:不重复的走过所有的点,并且是回路
//哈密尔顿环:不重复的走过所有的点,并且是回路 //能找出所有的环 int vi[1001],visted[1001],num[1001],g[1001][1001]; int length; int ans[1001]; //保存答案 int n,m,x; void print(){ for(int i=1;i<length;i++) cout<<ans[i]<<" "; cout<<ans[length]<<endl; } void dfs(int last,int i){ //上次访问的last,这次的i visted[i]=1; vi[i]=1; //标记 for(int j=1;j<=num[i];j++){ if(g[i][j]==x&&g[i][j]!=last){ ans[++length]=j; print(); //找到一个环,输出 length--; break; } if(!visted[g[i][j]]) dfs(i,g[i][j]); //遍历所有与i关联的点 } length--; visted[i]=0; //回溯 不标记vi[],因为vi表示是否在图中出现过 } int main(){ memset(visted,0,sizeof(visted)); memset(vi,0,sizeof(vi)); cin>>n>>m; int y; for(int i=1;i<=m;i++){ cin>>x>>y; g[x][++num[x]]=y; g[y][++num[y]]=x; } for(x=1;x<=n;x++){ if(!vi[x]) { length=0; dfs(0,x); } //以每一个点为起点遍历,因为不是任一个点都可以遍历出环的 } return 0; }
最短路径
dijkstra
原文:https://www.cnblogs.com/shirlybaby/p/12370182.html