题目:
给出一个结点d和一个无向图中所有的边,按字典序输出这个无向图中所有从1到d的路径。
思路:
1.看到紫书上的提示,如果不预先判断结点1是否能直接到达结点d,上来就直接dfs搜索的话会超时,于是就想到了用并查集来预先判断是否属于同一个连通分量。
2.可以将与d属于同一个连通分量的点用一个数组保存起来,然后dfs搜索这个数组就可以了,这也就是只搜索了与d在一个连通分量里的点。
3.当搜索到d的时候就输出路径。
代码:
#include <bits/stdc++.h> #define inf 0x3f3f3f3f #define MAX 1e3 #define FRE() freopen("in.txt","r",stdin) #define FRO() freopen("out.txt","w",stdout) using namespace std; typedef long long ll; const int maxn = 22; bool mp[maxn][maxn]; int fa[maxn],d,lk[maxn],vis[maxn]; int idx,path[maxn],cnt;void init(){for(int i=0; i<maxn; i++){fa[i] = i;}memset(lk,0,sizeof(lk));memset(vis,0,sizeof(vis));memset(mp,0,sizeof(mp));memset(path,0,sizeof(path)); }int _find(int x){//并查集查找祖先return fa[x]==x ? x : fa[x] = _find(fa[x]); }void mergeNode(int x,int y){//合并不属于同一个连通分量的两个点int tx = _find(x),ty = _find(y);if(tx != ty){fa[tx] = ty;} }bool isLinked(int x,int y){//判断两个点是不是属于同一个连通分量if(_find(x)!=_find(y)){return false;}return true; }void DFS(int now, int MX){if(now==d){//搜索到d就输出;路径cnt++;printf("1");for(int i=0; i<MX; i++){printf(" %d",path[i]);}printf("\n");}else{//cout<<now<<endl;for(int i=1; i<idx; i++){int u = lk[i];if(!vis[u] && mp[now][u]){vis[u] = true;path[MX] = u;//这里其实没必要另开一个数组保存路径,在下一个循环的时候当前的路径已经输出或没用了DFS(u,MX+1);vis[u] = false;}}} }void check(){for(int i=0; i<idx; i++){printf("%d ",lk[i]);}printf("\n"); }int main(){//FRE();int kase=0;while(scanf("%d",&d)!=EOF){int st,en;init();while(scanf("%d%d",&st,&en)&&st){mp[st][en] = 1;mp[en][st] = 1;mergeNode(st,en);}printf("CASE %d:\n",++kase);if(isLinked(1,d)==false){printf("There are 0 routes from the firestation to streetcorner %d.\n",d);}else{idx=0;for(int i=1; i<maxn; i++){//找到与d在同一个连通分量里边的点并保存if(isLinked(i, d)){lk[idx++] = i;}}sort(lk,lk+idx);//从小到大排序,保证字典序//check();cnt = 0;DFS(1, 0);printf("There are %d routes from the firestation to streetcorner %d.\n",cnt,d);}}return 0; }