1.深度优先搜索(DFS)
对于任意的一个图,有一点x,我们寻找与它连通的所有深度更深的点y(若没有,回到上一个点)。若y被访问过,回到x。反之,访问y。如此循环往复。
若x被访问过,则x的父节点也一定被访问过。每条边至多被访问2次,每个点至多被访问一次。
inline void dfs(int x){ int i; vis[x]=1; for(i=1;i<=n;i++){ if(mp[x][i]&&!vis[i]){ dfs(i); } } }
使用DFS枚举已知集合的所有子集状态
对于一个元素a[i]有两种选择:选/不选。于是我们DFS求出来的树同时是一棵二叉树。先沿着选的方向到底,在一步步回溯,直到遍历结束。
inline void dfs(int x){ if(x>n){ //得到了一个子集 return ; } s[++tot]=a[x]; dfs(x+1); tot--; dfs(x+1); } (5)DFS枚举1~n的全排列 inline void dfs(int x){ if(x>n){ //得到了一个排列 return ; } int i; for(i=1;i<=n;i++){ if(!used[i]){ //没有使用过 p[x]=i; used[i]=1; //标记使用 dfs(x+1); used[i]=0; //清空,准备下一步 } } }
DFS判断图中有无环
分析:判断环我们只要判断图中有无返祖边(后向边)即可。返祖边:两点u,v,且u->v。vis[v] = 1,说明v已经被访问,但其子孙后代还没有被访问完。而u又指向说明u就是v的子孙后代,u->v是一条后向边(返祖边)。
广度优先搜索(BFS)
运用了队列知识
void bfs(){ q[tl++]=s; while(hd!=tl){ x=q[hd++]; //弹队头 for(i=1;i<=n;i++){ if(mp[x][i]&&!vis[i]){ //连通且没被访问 q[tl++]=i; //加队尾 vis[i]=1; //标记访问 } } } }
3.记忆化搜索(DFS优化)
省去了重复的部分,加速
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define N 1000 #define M 1000 using namespace std; int n,m; int u,v,c; int s,to[M],l[M],ne[M],pre[N]; void add(int u,int v,int c) //加边函数,邻接表存储 { to[++s]=v; l[s]=c; ne[s]=pre[u]; pre[u]=s; } int f[N]; bool vi[N]; int cal(int k) { if(vi[k]) return f[k]; vi[k]=true; for(int i=pre[k];i;i=ne[i]) { int x=to[i]; f[k]=max(f[k],cal(x)+l[i]); } return f[k]; } int main() { cin>>n>>m; while(m--) { cin>>u>>v>>c; add(u,v,c); } for(int i=1;i<=n;i++) cout<<i<<' '<<cal(i)<<endl; return 0; }