UVa #208 Firetruck (习题7-1)

86 篇文章 0 订阅

题意很简单:给一个结点的邻接表,让按照字典序打印出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;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值