UVa 208 - Firetruck 回溯+剪枝 数据

题意:构造出一张图,给出一个点,字典序输出所有从1到该点的路径。

裸搜会超时的题目,其实题目的数据特地设计得让图稠密但起点和终点却不相连,所以直接搜索过去会超时。

只要判断下起点和终点能不能相连就行了,可以用并查集也可以用floyd算法,这样就能过了。

但是这个方法不是很完美的,如果两点之间只有一条线相连,而图又是稠密图,这样也很容易超时,数据强电就会挂掉。

可以把算法改进一下:是先从终点出发,无回溯的走遍和终点相连的所有点并标记,然后从起点出发,DFS判断下标记,这样就不会多走很多路了。另一个方法是在把点并入并查集的时候不考虑起点,然后DFS只走和终点同一集合的点。

某位大神的博客上说Tarjan算法也可以很好的实现。

我的代码是floyd算法:

 

#include <cstdio>

#include <cstring>

const int maxn = 999999;

int t = 0, v, sum, f;

int g[30][30], vis[30], floyd[30][30], rec[30];



void dfs(int x, int n) {

	if (x == f) {

		printf("1");

		for (int i = 1; i < n - 1; i++)

			printf(" %d", rec[i]);

		printf(" %d\n", f);

		sum++;

		return;

	}

	for (int i = 1; i <= v; i++) {

		if (!vis[i] && g[x][i] == 1 && floyd[f][i] != maxn) {

			rec[n] = i;

			vis[i] = 1;

			dfs(i, n + 1);

			vis[i] = 0;

		}

	}

}



int main() {

	int x, y, cas = 1;

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

		v = 0;

		for (int i = 1; i <= 21; i++)

			for (int j = 1; j <= 21; j++)

				g[i][j] = floyd[i][j] = maxn;

		while (scanf("%d%d", &x, &y) && (x || y)) {

			g[x][y] = g[y][x] = 1;

			floyd[x][y] = floyd[y][x] = 1;

			if (x > v) v = x;

			if (y > v) v = y;

		}

		for (int k = 1; k <= v; k++)

			for (int i = 1; i <= v; i++)

				for (int j = 1; j <= v; j++)

					if (floyd[i][k] + floyd[k][j] < floyd[i][j])

						floyd[i][j] = floyd[i][k] + floyd[k][j];

		vis[1] = 1;

		sum = 0;

		printf("CASE %d:\n", cas++);

		dfs(1, 1);

		printf("There are %d routes from the firestation to streetcorner %d.\n", sum, f);

	}

	return 0;

}

 


Input:

 

14

1 8

2 11

3 4

3 6

4 14

5 6

5 8

6 11

6 12

8 14

9 14

10 14

11 14

0 0


 

Output:

 

CASE 1:

1 8 5 6 3 4 14

1 8 5 6 11 14

1 8 14

There are 3 routes from the firestation to streetcorner 14.


 

 

你可能感兴趣的:(uva)