图论总结(1)深度优先遍历

来源:互联网 发布:为什么程序员生女儿 编辑:程序博客网 时间:2024/06/05 14:31

感觉图论嗑得差不多了做点总结吧。

听所图论题套模板,下面就给一些模板吧。

1.DFS框架(依次递归访问当前节点的所有相邻节点):

vector<int>G[maxn];int vis[maxn];void dfs(int u){vis[u]=1;PREVISIT(u);//访问u前的操作int d=G[u].size();for(int i=0;i<d;i++){int v=G[u][i];if(!vis[u])dfs(v);}POSTVISIT(u);//访问u后的操作 }
2.欧拉回路(一笔画问题):

如果一个图存在一笔画(不重复走完所有的边),则一笔画的路径叫做欧拉路,如果最后又回到了起点,那这个路径叫做欧拉回路。

我们定义奇点是指跟这个点相连的边数目有奇数个的点,给出下面两个定理。

定理1:存在欧拉路的条件:图是联通的,有且只有两个奇点。

定理2:存在欧拉回路的条件:图是联通的,没有奇点。

下面给出模板:

先遍历找到较小奇点从这个奇点开始 

int G[maxn][maxn],circuit[maxn],circuitpos;//用邻接矩阵保存边void euler(int i){int j;for(j=1;j<=n;j++)if(G[i][j]){G[i][j]=G[j][i]=0;euler(j);}circuit[++circuitpos]=i;//用来记录路径}
判断是欧拉路还是欧拉回路直接用定理,遍历一次就行。

不足的是上程序只能找一个回路,具体问题还需作出相应修改。

3.哈密顿环

和欧拉回路很像,只是将不重复走过所有边改为了不重复走过所有点。

直接给模板:


//ÿ¸öµã¶¼×÷ΪÆðµã³¢ÊÔ·ÃÎÊ£¬Ó¦Îª²»ÊÇ´ÓÈκÎÒ»µã¿ªÊ¼¶¼ÄÜÕÒµ½Õû¸öͼint ans[maxn],vis[maxn],vl[maxn];vector<int>G[maxn][maxn];int cnt,x;void print(){int i;for(i=1;i<=cnt-1;i++)cout<<ans[i]<<' ';cout<<ans[cnt]<<endl;}void dfs(int i,int last){vis[i]=1;vl[i]=1;ans[++cnt]=i;for(int j=0;j<G[i].size();j++){if(G[i][j]==x&&G[i][j]!=last){ans[++cnt]=G[i][j];print();cnt--;break;}if(!vis[G[i][j]])dfs(G[i][j],i);}cnt--;vis[i]=0;//»ØËݵĹý³Ì }void solve(){memset(vl,0,sizeof(vl));memset(vis,0,sizeof(vis));for(x=1;x<=n;x++)//ÿ¸öµã¶¼×÷ΪÆðµã³¢ÊÔ·ÃÎÊ£¬Ó¦Îª²»ÊÇ´ÓÈκÎÒ»µã¿ªÊ¼¶¼ÄÜÕÒµ½Õû¸öͼ//ÿ¸öµã¶¼×÷ΪÆðµã³¢ÊÔ·ÃÎÊ£¬Ó¦Îª²»ÊÇ´ÓÈκÎÒ»µã¿ªÊ¼¶¼ÄÜÕÒµ½Õû¸öͼ { if(!vl[x]){ cnt=0; dfs(x,0); } }}
上程序可以一次性找出所有的哈密顿环。

4.求联通分量(无向图):

种子填充问题

求联通分量个数

模板:

int G[maxn][maxn],vis[maxn];void dfs(int i,int id){vis[i]=id;for(int j=1;j<=n;j++)if(!vis[j]&&G[i][j]){dfs(j,id);}}void solve(int i){int cnt=0;//用来记录编号memset(vis,0,sizeof(vis));int ans=0;for(int i=1;i<=n;i++)if(!vis[maxn]){dfs(i,++cnt);ans++;}}
5.二分图判定
二分图定义自己百度去。

给出二分图的一种等价说法:可以把每个节点着以黑色和白色之一,是的每条边的两个端点颜色不同。

不难发现非连通图是二分图当且仅当每个连通分量是二分图,因此我们仅考虑无向连通图。

下面用DFS来给任意无向图G进行黑白着色。
首先假定节点1是黑色的(白色也一样)。

int color[maxn];bool bipartite(int u){for(int i=0;i<G[i].size();i++){int v=G[u][i];if(color[v]==color[u])return false ;if(!color[v]){color[v]=3-color[u];if(!bipartite(v))return false ;}}return true;}
我们用颜色1,2表示黑色和白色,0表示未涂色,就不需要vis数组了。记得将color数组初始化为0。


原创粉丝点击