UVA - 208 Firetruck(并查集+dfs)

题目:

给出一个结点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;
}

猜你喜欢

转载自www.cnblogs.com/sykline/p/10325726.html