题目:
给出一个结点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(" "); }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(" "); } 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: ",++kase); if(isLinked(1,d)==false){ printf("There are 0 routes from the firestation to streetcorner %d. ",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. ",cnt,d); } } return 0; }