题目大意
给出终点,然后给出哪两个点连通,注意这里的连通是没有方向的那种连通。然后按字典序输出所有可能从1到终点的路径。
思路
由于1可能到达不了终点,盲目暴力肯定会超时,所以可以先用并查集看1和终点是否连通,然后在开始用dfs打印路径。这里的dfs写法是看一位大佬的写法才豁然开朗。
代码
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 21;
int pre[maxn]; // 父节点
bool G[maxn][maxn]; // 记录两点是否连通
int ans;
int vis[maxn];
int en; // 最终要到达的目标位置
vector<int> res; // 保存路径结果
int find(int x) {
int r = x;
int temp;
while(r != pre[r]) {
r = pre[r];
}
while(x != r) { // 路径压缩
temp = pre[x];
pre[temp] = r; // 把每一个都连到根节点
x = temp;
}
return r;
}
void dfs(int cur)
{
if (cur == en){
ans++;
for (int i = 0; i != res.size(); i++)
printf("%d%c", res[i], i == res.size()-1 ? '\n' : ' ');
return;
}
for (int i = 2; i <= 21; i++) {
if (!vis[i] && G[cur][i]) {
vis[i] = 1;
res.push_back(i);
dfs(i);
vis[i] = 0;
res.pop_back();
}
}
}
int main() {
freopen("input.txt", "r", stdin);
int x, y;
int kase = 0;
while(~scanf("%d", &en)) {
for(int i = 1; i <= maxn; i++) {
pre[i] = i;
}
memset(G, false, sizeof(G));
while(scanf("%d%d", &x, &y) && x && y) {
G[x][y] = G[y][x] = true;
int rx = find(x);
int ry = find(y);
if (rx != ry) {
pre[rx] = ry;
}
}
ans = 0;
printf("CASE %d:\n", ++kase);
int fen = find(en);
int fbe = find(1);
if (fbe != fen) {
goto END; // 用并查集防止超时
}
memset(vis, 0, sizeof(vis));
res.clear();
res.push_back(1);
vis[1] = 1;
dfs(1);
END:
printf("There are %d routes from the firestation to streetcorner %d.\n", ans, en);
}
return 0;
}