双向搜索(UVA 208 Firetruck)

4 篇文章 0 订阅
3 篇文章 0 订阅

UVA 208 Firetruck

Description:

The Center City re department collaborates with the transportation department to maintain maps of the city which re ects the current status of the city streets. On any given day, several streets are closed for repairs or construction. Fire ghters need to be able to select routes from the restations to res that do not use closed streets.
Central City is divided into non-overlapping re districts, each containing a single restation. When a re is reported, a central dispatcher alerts the restation of the district where the re is located and gives a list of possible routes from the restation to the re.

You must write a program that the central dispatcher can use to generate routes from the district restations to the res.

Input:

The city has a separate map for each re district. Streetcorners of each map are identi ed by positive integers less than 21, with the restation always on corner #1. The input le contains several test cases representing different res in different districts.

The rst line of a test case consists of a single integer which is the number of the streetcorner closest to the re.

he next several lines consist of pairs of positive integers separated by blanks which are the
adjacent streetcorners of open streets. (For example, if the pair 4 7 is on a line in the le, then
the street between streetcorners 4 and 7 is open. There are no other streetcorners between 4 and
7 on that section of the street.)

The nal line of each test case consists of a pair of 0’s.

Output

For each test case, your output must identify the case by number (
CASE 1:
',

CASE 2:
‘, etc). It must
list each route on a separate line, with the streetcorners written in the order in which they appear on
the route. And it must give the total number routes from restation to the re.
Include only routes
which do not pass through any streetcorner more than once.
(For obvious reasons, the re
department doesn’t want its trucks driving around in circles.)
Output from separate cases must appear on separate lines.

Sample Input

6
1 2
1 3
3 4
3 5
4 6
5 6
2 3
2 4
0 0
4
2 3
3 4
5 1
1 6
7 8
8 9
2 5
5 7
3 1
1 8
4 6
6 9
0 0

Sample Output

CASE 1:
1 2 3 4 6
1 2 3 5 6
1 2 4 3 5 6
1 2 4 6
1 3 2 4 6
1 3 4 6
1 3 5 6
There are 7 routes from the firestation to streetcorner 6.
CASE 2:
1 3 2 5 7 8 9 6 4
1 3 4
1 5 2 3 4
1 5 7 8 9 6 4
1 6 4
1 6 9 8 7 5 2 3 4
1 8 7 5 2 3 4
1 8 9 6 4
There are 8 routes from the firestation to streetcorner 4.

题意:
就是起点每次都是1,然后输入终点。输入路的端点,并且是无向图。然后找到所有从1到终点的路径。

思路:

  • 其实这个题做了好多遍都没过,一开始读题知道是要找所有的路径,所以用深搜,用二维vector模拟邻接表。用path[maxn]记录路径,depth记录深度,每次找到路径后,就输出。但是超时。

  • 再一想,找到所有路径不就是应该用深搜吗?哦对,应该还要剪枝。那这个题应该如何剪枝?一开始想的是用两个集合canR和notR分别表示能到和不能到的点,当有一条路径确定的时候,就把这条路上的所有点都insert,当走这个点走不到终点时,并且这个点不在canR中的时候,insert到notR。然后每次进入一个点前先要判断是notR有没有,有就不访问了。可是wa了。

  • 为啥wa?哦,因为当有一个点走不到终点时,可能下一次能到终点。比如有一个点i可以到终点,但是到这个点之前我们是先搜索完了这个点的周围的所有点,就导致这个点出不去了(dfs的判重啊)。所以可以到终点的点,却被我们拉近了黑名单(notR)。

  • 然后想,是不是优化的太过了?那这样优化实现不了,就退一步。只看你这个点是不是与终点在一个连通子图内就好了。不在一个连通子图内肯定到不了终点。所以先逆向搜索,从终点出发bfs,这样就可以遍历终点所在的连通子图,标记一下,然后dfs的时候就判断就好了。

AC代码

    #include<iostream>
    #include<cstdio>
    #include<vector> 
    #include<algorithm>
    #include<cstring>
    #include<set>
    #include<queue>
    using namespace std;

    int endNum;               //表示起点和终点的标号 
    vector<vector<int > > mapV(25);   //map 表示rode 
    int path[25];             //路径 
    int visit[25];            //标记数组 是否访问过
    int isLink[25];           //用于判断这些点是否与终点连通 
    int nodeNum;              //路的条数 
    int depth;                //路的长度 

    void dfs(int x)
    {
        //边界条件
        if(x == endNum) 
        {
            nodeNum++;  
            for(int i = 0;i < depth ; i++)
            {   
                if(path[i] == endNum)
                {
                    printf("%d\n",endNum);
                    break;
                }

                else 
                {
                    printf("%d ",path[i]);
                }

                //到达这里说明此路上的点可以到达
            }

            return ; 
        }

        //找其他路
        int n = mapV[x].size();
        for(int j = 0 ; j < n ;j++)
        {
            //未访问过  并且是可以达到的 
            if(visit[mapV[x][j]] == 0 && isLink[mapV[x][j]] == 1)  
            {
                visit[mapV[x][j]] = 1; 
                path[depth] = mapV[x][j];
                depth++;
                dfs(mapV[x][j]);                    
                depth--;
                visit[mapV[x][j]] = 0;
            }
        }
    }

    //用于把与终点联通的点标记 避免搜索与终点不连通的点 
    void bfs(int x)
    {
        queue<int > q;
        //初始结点入队
        q.push(x);

        while(!q.empty())
        {
            int temp =  q.front();
            q.pop();

            isLink[temp] = 1;

            //所有关联的节点入队 
            int n = mapV[temp].size();
            for(int j = 0;j < n; j ++)
            {
                if(visit[mapV[temp][j]] == 0)
                {
                    visit[mapV[temp][j]] = 1;
                    q.push(mapV[temp][j]);
                }

            }
        }   
    } 

    int main()
    {
        int caseN = 1;
        while(scanf("%d",&endNum) != EOF)
        {       
            for(int i=0;i<25;i++)
            {
                mapV[i].clear(); 
            }
            memset(visit,0,sizeof(visit));
            memset(path,0,sizeof(path));
            memset(isLink,0,sizeof(isLink)); 

            int s,e;           //一条路的起点和终点 
            while(scanf("%d %d",&s,&e) && !(s==0 && e==0))
            {
                mapV[s].push_back(e);
                mapV[e].push_back(s);
            }

            for(int i = 0;i < 25; i++)
                sort(mapV[i].begin(),mapV[i].end());

            nodeNum = 0;      //路的条数 
            depth=1;          //一条路的长度 
            path[0] = 1;
            visit[1] = 1;
            printf("CASE %d:\n",caseN);

            //在搜索前先优化,也就是说不搜索与终点不联通的点
            bfs(endNum); 
            memset(visit,0,sizeof(visit));

            dfs(1); 
            printf("There are %d routes from the firestation to streetcorner %d.\n",nodeNum,endNum);
            caseN ++;
        }

        return 0;
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值