题意很简单:给一个结点的邻接表,让按照字典序打印出1号结点到n号结点的全部路径。
先给邻接表排序方便按照字典序打印,之后一个dfs即可。
维护一个结点路径的全局变量,每次到达结点n即可打印
比较奇葩的一点是(书里也说了),每次必须上来就判断一下从1号结点出发是否能到达节点n,否则会TLE(不知道这么设置测试数据的意义在哪里,可能是为了考察选手的解题习惯?以后也应该注意这种预判)。
一开始我想不出什么判断这个可行性的方法,只好上board看看。发现大家在用Floyd算法,果断学习了一下:
Floyd的基本思想是非常典型的动态规划递推:
初始化dist矩阵,存储已知的两两结点之间的距离。距离未知或者不连通的两个结点,距离用正无穷表示
最外层枚举所有结点,设为k
中间层枚举除了k以外的所有结点,设为 i
内层同样也是枚举除了k以外的所有结点,设为 j
如果当前距离矩阵中 dist[i][j] > dist[i][k] + dist[k][j] ,也就是说从 i 出发经过 k 到达 j 的走法要优于已知的走法,那么就更新 dist[i][j] = dist[i][k] + dist[k][j]
算法运行完毕后,dist矩阵就变成了一个最短路径矩阵。无法联通的结点之间的距离是正无穷。利用这个正无穷就可以判断是否可以从结点1到达n。
Floyd的时间复杂度是n^3(三层枚举循环), 空间复杂度是n^2(距离矩阵)
Run Time: 0.015s
#define UVa "7-1.208.cpp"
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
//Global Variables.
int n, cnt;
int route[30];
vector<int> adjacent_list[30];
int vis[30];
/
int dfs(int u, int d) {
if(u == n) {
for(int i = 0; i < d; i ++) printf("%d ", route[i]);
printf("%d\n", u);
cnt ++;
return 1;
}
else {
// printf("%d %d\n", u, d);
route[d] = u;
for(int i = 0; i < adjacent_list[u].size(); i ++) {
int v = adjacent_list[u][i];
if(!vis[v]) {
vis[v] = 1;
dfs(v, d+1);
vis[v] = 0;
}
}
}
}
int main() {
int kase = 1;
while(scanf("%d", &n) != EOF) {
printf("CASE %d:\n", kase++);
memset(route, 0, sizeof(route));
memset(vis, 0, sizeof(vis));
vis[1] = 1;
cnt = 0;
int INF = 100000;
int a, b;
for(int i = 0; i < 30; i ++) adjacent_list[i].clear();
int d[25][25];
for(int i = 0; i < 25; i ++) for(int j = 0; j < 25; j ++) d[i][j] = INF;
while(scanf("%d%d", &a, &b) && a && b) {
d[a][b] = 1;
d[b][a] = 1;
adjacent_list[a].push_back(b);
adjacent_list[b].push_back(a);
}
//Floyd
for(int k = 0; k < 25; k ++) for(int i = 0; i < 25; i ++) for(int j = 0; j < 25; j ++) if(d[i][j] > d[i][k] + d[j][k]) d[i][j] = d[i][k] + d[j][k];
if(d[1][n] != INF) {
for(int i = 0; i < 30; i ++) sort(adjacent_list[i].begin(), adjacent_list[i].end());
dfs(1, 0);
}
printf("There are %d routes from the firestation to streetcorner %d.\n", cnt, n);
}
return 0;
}