(UVA - 208)Firetruck(路径输出问题,回溯+并查集/floyd算法+dfs)

27 篇文章 0 订阅
27 篇文章 0 订阅

题目链接: https://vjudge.net/problem/UVA-208

题意:输入一个n(n<=20)个节点的无向图以及某个节点k,按照字典序从小到大顺序输出从节点1到节点k的所有路径,要求节点不能重复。

分析:路径输出问题,路径的第一个和最后一个点是固定的,可以用dfs从小到大搜索,回溯求出所有的路径记录并输出。 注意要提前判断节点1是否可以到达节点k,不然会TLE。

提前判断能否到达,我写了两种:1.并查集 2.floyd算法
并查集当然是可以判断的,floyd算法可以用是因为数据n不是特别大

#include<cstdio>
#include<set>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define mem(a,n) memset(a,n,sizeof(a))
typedef long long LL;

const int N=25;
const int INF=0x3f3f3f3f;
int a[N][N],d[N][N];
int n,vis[N],ans,b[N];
int MAX,par[N];

#define same(x,y) Find(x)==Find(y)
void floyd()///floyd算法求最短路径,在此题中起判断作用
{
    for(int k=1;k<=MAX;k++)
        for(int i=1;i<=MAX;i++)
        for(int j=1;j<=MAX;j++)
        d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
void init()
{
    for(int i=0; i<N; i++)
        par[i]=i;
}
int Find(int x)
{
    return par[x]==x?x:Find(par[x]);
}
void unite(int x,int y)
{
    x=Find(x);
    y=Find(y);
    if(x!=y)
        par[x]=y;
}
void dfs(int cur,int pos)///搜索所有的可行路径
{
    if(cur==n)///可以到达点n
    {
        ans++;///可行方案数+1
        printf("1");
        for(int i=1; i<pos-1; i++)
            printf(" %d",b[i]);
        printf(" %d\n",n);
        return ;
    }
    for(int i=1; i<=MAX; i++)///依次遍历
    {
        if(!vis[i]&&a[cur][i]==1&&same(i,n))///same()函数起判断作用,a[cur][i]==1代表必须有路径,vis判重
        {
            b[pos]=i;
            vis[i]=1;
            dfs(i,pos+1);
            vis[i]=0;///回溯
        }
    }
}
int main()
{
    int cas=1;
    while(~scanf("%d",&n))
    {
        init();
        printf("CASE %d:\n",cas++);
        MAX=0;MAX记录无向图节点的最大编号值
        mem(d,INF);
        mem(a,0);
        int x,y;
        while(~scanf("%d%d",&x,&y)&&x&&y)
        {
            unite(x,y);
            a[x][y]=a[y][x]=1;///=1表示联通
            MAX=max(MAX,max(x,y));
        }
//       floyd();
        vis[1]=1;
        ans=0;
        dfs(1,1);///从节点1开始搜索
        printf("There are %d routes from the firestation to streetcorner %d.\n",ans,n);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值