您的位置:首页 > 其它

UVa 208 - Firetruck,双向搜索进行剪枝

2012-07-17 00:27 351 查看


208 - Firetruck667516.87%

153454.76%

题目链接:

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=108&page=show_problem&problem=144

类型: 回溯法



原题:

The Center City fire department collaborates with the transportation department to maintain maps of the city which reflects the current status of the city streets. On any given day, several streets are
closed for repairs or construction. Firefighters need to be able to select routes from the firestations to fires that do not use closed streets.

Central City is divided into non-overlapping fire districts, each containing a single firestation. When a fire is reported, a central dispatcher alerts the firestation of the district where the fire is
located and gives a list of possible routes from the firestation to the fire. You must write a program that the central dispatcher can use to generate routes from the district firestations to the fires.

Input

The city has a separate map for each fire district. Streetcorners of each map are identified by positive integers less than 21, with the firestation always on corner #1. The input file contains several
test cases representing different fires in different districts.

The first line of a test case consists of a single integer which is the number of the streetcorner closest to the fire.
The 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 file, 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 final 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 firestation to the fire. Include only routes which do not pass through any streetcorner more than once. (For obvious reasons, the fire department doesn't want its trucks driving around
in circles.)
Output from separate cases must appear on separate lines.

The following sample input and corresponding correct output represents two test cases.

题目大意:
城市消防中心与交通部门有合作,目的是为了获取城市街道的实时状态。
每一天都会有一些街道因为维修或者施工而关闭,所以为了节约时间不走冤枉路,消防员需要选择一条不经过关闭的街道的路线到达火灾发生地。
该城市被划分为不重叠的火区, 每个火区由一个消防站负责。
当火灾发生接到报警时,中心调度员MM会发送警报到管辖该区域的消防站, 并且提供多条从消防站到火灾发生地的路线供选择。
你想追调度员MM, 所以你决定编写一个程序帮助中心调度员MM生成从消防站到灾区的路线。

该城市的每个火区都有一张单独的地图。
地图上的街道路口(Streetcorner)被标志为一个不超过21的整数(每张地图的街道路口数量不超过21), 并且每张地图的消防站
的编号都是1(on corner #1).

分析与总结:
一看到这题,看到过题率这么低以为很难,但是看到完题目觉得挺容易,很快就写好了,提交后却TLE了。。。
在此TLE。。。
又一次TLE。。。
于是问了谷哥, 学到了一样新东西。

之所以会超时,原因在于可能会有很多条路是完全到达不了目标的,比如,南京到北京,需要往北边走,但是路是非常多的,
除了往北边的路,还有往南边,西边,东边的路,而走这些方向走无疑是南辕北辙的, 走到死也到不了北京,就算绕地球一圈
到达终点,但是黄花菜早就已经凉了(调度员MM还等着你呢~~)。而超时的原因就出在了这里。

所以, 从起点开始搜索之前,很有必要先确定一下有那些路是可以到达目标的。

如何确定那些路可以到目标呢? 我们只需要先从目标点开始进行搜索,把所有搜索到得路径都进行标记。

然后,再从起点处进行搜索,在搜索之前,要先判断一下这个路径是否有被之前标记过,如果没有被标记,那么说明它是不可能
走到目标处的。这样的话,就不会盲目地去走了,也大大提高了效率。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define MAXN 22
using namespace std;
int G[MAXN][MAXN], route[MAXN], edge[MAXN], cnt, end, numRoute;
bool vis[MAXN], used[MAXN], occur[MAXN];

void search(int cur, int u){
    if(u == end){
        ++numRoute;
        printf("%d", route[0]);
        for(int i=1; i<cur; ++i)
            printf(" %d", route[i]);
        printf("\n");
        return;
    }
    int v;
    for(int i=1; i<cnt; ++i)if(used[edge[i]]){// 回溯时判断这条路经是否可以到达终点
        int v=edge[i];
        if(G[u][v] && !vis[v]){
            vis[v] = true;
            route[cur] = v;
            search(cur+1, v);
            vis[v] = false;
        }
    }
}

int que[10000];
// bfs预处理, 用dfs也可
void bfs(int u){
    int front=0, rear=0;
    que[rear++] = u;
    while(front < rear){
        int t = que[front++];
        for(int i=0; i<cnt; ++i)if(!used[edge[i]] && G[t][edge[i]]){
            used[edge[i]] = true; //经过的标志为true
            que[rear++] = edge[i];
        }
    }
}

int main(){
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
#endif
    int u,v,cas=1;

    while(scanf("%d", &end) != EOF){

        memset(G, 0, sizeof(G));
        memset(occur, 0, sizeof(occur));
        while(scanf("%d %d", &u, &v)!=EOF){
            if(!u && !v) break;
            occur[u] = occur[v] = true;
            ++G[u][v];
            ++G[v][u];
        }
        cnt = 0;
        for(int i=1; i<MAXN; ++i)if(occur[i]){
            edge[cnt++] = i;
        }

        memset(vis, 0, sizeof(vis));
        memset(used, 0, sizeof(used));
        vis[end] = true;
        used[end] = true;
        bfs(end);

        printf("CASE %d:\n", cas++);
        memset(vis, 0, sizeof(vis));

        route[0] = 1;
        vis[1] = true;
        numRoute = 0;
        search(1, 1);
        printf("There are %d routes from the firestation to streetcorner %d.\n", numRoute, end);
    }
    return 0;
}


——  生命的意义,在于赋予它意义。     原创 http://blog.csdn.net/shuangde800 , By   D_Double  [b](转载请标明)[/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: