UVa 208 救火车

题意:先给出离出火地点最近的路口,然后给出一些之间通畅的路口。要求给出所有从1号路口到火灾事故点的不含回路的简单路径。

思路:方法很容易想到,dfs即可。但是简单的dfs会超时,3s+. 之后看别人用了并查集,去了解了下并查集的思想。这里可以通过并查集提前判断一个路口是否和火灾路口想通,如果不通,则直接剪枝了。别看仅这一个优化,最后AC时间0.022,性能提升还是很多的。因为你早早地剪去一个结点,由它延伸下去的很多种情况都一并剪枝了的。也可以分析下直接dfs的复杂度,粗略地估算解答树结点的个数:1+20+19*19+19*18+...+19*1=3631个(最坏情况下,21个结点全连通)

并查集的思想见上篇博客讲解。这里写的并查集的代码也不是最优的union。

注意:PE错误提示了输出的时候是每个路径最后结点后面没有空格。

Code:

#include<stdio.h>
#include<string.h>

void dfs(int cur, int fr, int max);
int find(int x);
void unn(int x, int y);

int p[25];
int g[25][25];
int vis[25];//不用0号结点,编号是从1到n 
int path[25];
int cnt;
int num;//路径数 

int main()
{
  //freopen("208.in","r",stdin);
  //freopen("208.out","w",stdout);
    
  int fire;
  int a,b;
  int t=0;
  while(scanf("%d",&fire)==1)
  {
    //初始化
    memset(g,0,sizeof(g));
    memset(vis,0,sizeof(vis));
    memset(path,0,sizeof(path));
    for(int i=1;i<25;++i) p[i]=i;
    cnt=1;
    num=0; 
    printf("CASE %d:\n",++t);
    int max=0;
    path[0]=1;
    vis[1]=1;//vis[1]不是vis[0] 
    while(scanf("%d%d",&a,&b)==2 && a &&b)
    {
      max=a>max?a:max;
      max=b>max?b:max;
      g[a][b]=1;
      g[b][a]=1;        
      unn(a,b);                 
    }
    dfs(1,fire,max);
    printf("There are %d routes from the firestation to streetcorner %d.\n",num,fire);
  }
  return 0;
}

void unn(int x, int y)
{
  int xrt=find(x);
  int yrt=find(y);
  if(xrt!=yrt)
  {
    p[xrt]=yrt; 
  }
}

int find(int x)
{
  return x==p[x]?x:p[x]=find(p[x]);    
}

void dfs(int cur, int fr, int max)
{
  if(cur==fr)
  {
    num++;
    for(int i=0;i<cnt-1;++i)
      printf("%d ",path[i]);
    printf("%d\n",path[cnt-1]);
    return ;           
  }
  for(int i=2;i<=max;++i)
  {
    int ffr=find(fr);
    if(g[cur][i] && !vis[i] && find(i)==ffr)
    {
      vis[i]=1;
      path[cnt++]=i;
      dfs(i,fr,max);
      //恢复
      cnt--;
      vis[i]=0; 
    }
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值