雙向搜索(UVA 208 Firetruck)

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;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章