习题7-1:消防车
题意:构造出一张图,给出一个点,字典序输出所有从1到该点的路径。
裸搜会超时的题目,其实题目的数据特地设计得让图稠密但起点和终点却不相连,所以直接搜索过去会超时。
只要判断下起点和终点能不能相连就行了,可以用并查集也可以用floyd算法,这样就能过了。
但是这个方法不是很完美的,如果两点之间只有一条线相连,而图又是稠密图,这样也很容易超时,数据强电就会挂掉。
可以把算法改进一下:是先从终点出发,无回溯的走遍和终点相连的所有点并标记,然后从起点出发,DFS判断下标记,这样就不会多走很多路了。另一个方法是在把点并入并查集的时候不考虑起点,然后DFS只走和终点同一集合的点。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int k, n, m, ans, maxn;
bool Map[50][50];
bool vis[50];
bool floyd[50][50];
int e[30];
void dfs(int x, int d)
{
if(x == k)
{
printf("1");
for(int i = 1; i < d - 1; i++)
{
printf(" %d",e[i]);
}
printf(" %d\n",k);
ans++;
return;
}
for(int i = 1; i <= maxn; i++)
{
if(i == x)continue;
if(!vis[i] && Map[x][i] && floyd[i][k])
{
e[d] = i;
vis[i] = 1;
dfs(i, d + 1);
vis[i] = 0;
}
}
}
int main()
{
int cases = 0;
while(scanf("%d",&k) != EOF)
{
int a, b;
maxn = 0;
memset(Map, 0, sizeof(Map));
memset(floyd, 0, sizeof(floyd));///忘记初始化导致超时
memset(vis, 0, sizeof(vis));
while(scanf("%d%d", &a, &b) && (a || b))
{
Map[a][b] = Map[b][a] = 1;
floyd[a][b] = floyd[b][a] = 1;
maxn = max(maxn, max(a, b));
}
for(int k = 1; k <= maxn; k++)
for(int i = 1; i <= maxn; i++)
for(int j = 1; j <= maxn; j++)
floyd[i][j] = floyd[i][j] || (floyd[i][k] && floyd[k][j]);
ans = 0;
vis[1] = 1;
printf("CASE %d:\n",++cases);
dfs(1, 1);
printf("There are %d routes from the firestation to streetcorner %d.\n", ans, k);
}
return 0;
}