UVA 208 Firetruck 消防车(回溯 + 剪枝)

迷南。 2024-02-17 19:12 82阅读 0赞

题意:一个包含<=20个结点的无向图,输入一个结点k,求从1到的k的所有路径,要求字典序输出,并且结点不能重复。

思路:刚开始直接回溯,结果超时了;从终点出发,找到所有与终点连通的结点,存储在数组aa当中,之后排序(字典序输出嘛),这样的话当从起点无法到达终点时,减少了很多结点判断(剪枝)。想象一下当一个长度为20的路径>10的时候有断点,那么从起始位置1开始,肯定没有与g[1][i]相连的路径,很快就退出dfs了。

AC代码如下:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. const int maxn=20+2;
  6. int g[maxn][maxn]; //储存无向图
  7. int vis[maxn],aa[maxn]; //aa用于存储与目标点k联通的点集
  8. int path[maxn]; //输出路径保存 (下标从1开始)
  9. int k,total;
  10. int maxn2;
  11. void print(int tmp){
  12. printf("%d",path[1]);
  13. for(int i=2;i<=tmp;i++)
  14. printf(" %d",path[i]);
  15. printf("\n");
  16. }
  17. void dfs1(int cur){ //收集与目标点k联通的点集
  18. vis[cur]=1;
  19. aa[maxn2++]=cur;
  20. for(int i=1;i<=20;i++){
  21. if(!vis[i] && g[cur][i])
  22. dfs1(i);
  23. }
  24. }
  25. void dfs(int cur,int tmp){
  26. if(cur==k){
  27. print(tmp-1);
  28. total++;
  29. return ;
  30. }
  31. for(int i=0;i<=maxn2;i++){
  32. if(g[cur][aa[i]] && !vis[aa[i]]){
  33. vis[aa[i]]=1;
  34. path[tmp]=aa[i];
  35. dfs(aa[i],tmp+1);
  36. vis[aa[i]]=0;
  37. }
  38. }
  39. }
  40. int main(){
  41. int count1=0;
  42. while(scanf("%d",&k)==1){
  43. memset(g,0,sizeof(g));
  44. memset(vis,0,sizeof(vis));
  45. int a,b;
  46. while(scanf("%d%d",&a,&b)==2 && a){
  47. g[a][b]=1;
  48. g[b][a]=1;
  49. }
  50. maxn2=total=0;
  51. dfs1(k);
  52. sort(aa,aa+maxn2); //必须排序,题目要求字典序输出
  53. memset(vis,0,sizeof(vis));
  54. printf("CASE %d:\n",++count1);
  55. path[1]=vis[1]=1;
  56. dfs(1,2);
  57. printf("There are %d routes from the firestation to streetcorner %d.\n",total,k);
  58. }
  59. return 0;
  60. }

发表评论

表情:
评论列表 (有 0 条评论,82人围观)

还没有评论,来说两句吧...

相关阅读