最短路 + 记录路径 之 zoj 1456 Minimum Transport Cost (hdu 1385)

/*
考虑到测试数据中需要求解任意两点间的最短路,所以采用Floyd-Warshall算法
 
dp[i][j] = min(dp[i][k] + dp[k][j] + tax[k], dp[i][j]);
 
关键在于记录路径,并且要保证:if there are more minimal paths, output the lexically smallest one.
分两种情况讨论:
	(1)dp[i][j] > dp[i][k] + dp[k][j] + tax[k]
		直接更新dp[i][j],保证获得最短路
	(2)dp[i][j] == dp[i][k] + dp[k][j] + tax[k]
		看i节点的直接后继节点编号哪个更小,哪个小选哪个,保证获得 the lexically smallest one。
 
为记录路径:
	path[i][j] := 在节点i到节点j的最短路径上,i的直接后继节点编号。
	初始值:path[i][j] = j
	用这种办法可以记录路径的原因:
		有n个节点,从1->n的最短路径,假设是这样的1->2->3->4->...->n,则2->n的最短路径
		必然是2->3->4->...->n,3->n的最短路径必然是3->4->...->n,如果不是这样的,那么
		当前1->n的路径必然不是1->n的最短路径,与假设矛盾。
	通过循环即可获得1->n的完整最短路径。
*/
  1 #include <iostream>
  2 #include <cstdlib>
  3 #include <cstdio>
  4 #include <cstddef>
  5 #include <iterator>
  6 #include <algorithm>
  7 #include <string>
  8 #include <locale>
  9 #include <cmath>
 10 #include <vector>
 11 #include <cstring>
 12 #include <map>
 13 #include <utility>
 14 #include <queue>
 15 #include <stack>
 16 #include <set>
 17 using namespace std;
 18 const int INF = 0x3f3f3f3f;
 19 const int MaxN = 205;
 20 const int modPrime = 3046721;
 21 
 22 int N;
 23 int dp[MaxN][MaxN];
 24 int tax[MaxN];
 25 int path[MaxN][MaxN];
 26 
 27 
 28 void Solve()
 29 {
 30     for (int i = 0; i < N; ++i)
 31     {
 32         for (int j = 0; j < N; ++j)
 33         {
 34             path[i][j] = j;
 35         }
 36     }
 37     for (int k = 0; k < N; ++k)
 38     {
 39         for (int i = 0; i < N; ++i)
 40         {
 41             for (int j = 0; j < N; ++j)
 42             {
 43                 //dp[i][j] = min(dp[i][k] + dp[k][j] + tax[k], dp[i][j]);
 44                 if (dp[i][j] > dp[i][k] + dp[k][j] + tax[k])
 45                 {
 46                     dp[i][j] = dp[i][k] + dp[k][j] + tax[k];
 47                     path[i][j] = path[i][k];
 48                 }
 49                 else
 50                 {
 51                     if (dp[i][j] == dp[i][k] + dp[k][j] + tax[k])
 52                     {
 53                         if (path[i][j] > path[i][k])
 54                         {
 55                             path[i][j] = path[i][k];
 56                         }
 57                     }
 58                 }
 59             }
 60         }
 61     }
 62 
 63     int src, dsn;
 64     while ((~scanf("%d %d", &src, &dsn)) && !(src == -1 && dsn == -1))
 65     {
 66         printf("From %d to %d :\n", src, dsn);
 67         printf("Path: "); 
 68         int tmp = src - 1;
 69         printf("%d", src);
 70         while (tmp != dsn - 1)
 71         {
 72             printf("-->");
 73             printf("%d", path[tmp][dsn - 1] + 1);
 74             tmp = path[tmp][dsn - 1];
 75         }
 76         
 77 
 78         printf("\n");
 79         printf("Total cost : %d\n\n", dp[src - 1][dsn - 1]);
 80     }
 81 }
 82 
 83 int main()
 84 {
 85 #ifdef HOME
 86     freopen("in", "r", stdin);
 87     //freopen("out", "w", stdout);
 88 #endif
 89 
 90     while (~scanf("%d", &N) && N)
 91     {
 92         for (int i = 0; i < N; ++i)
 93         {
 94             for (int j = 0; j < N; ++j)
 95             {
 96                 scanf("%d", &dp[i][j]);
 97                 if (dp[i][j] == -1)
 98                 {
 99                     dp[i][j] = INF;
100                 }
101             }
102         }
103         for (int i = 0; i < N; ++i)
104         {
105             scanf("%d", &tax[i]);
106         }
107         Solve();
108     }
109 
110 
111 #ifdef HOME
112     cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl;
113     _CrtDumpMemoryLeaks();
114 #endif
115     return 0;
116 }
 
 

 

 

转载于:https://www.cnblogs.com/shijianming/p/5025609.html

这道题是一个典型的搜索问题,可以使用深度优先搜索(DFS)或广度优先搜索(BFS)来解决。以下是使用DFS的代码实现: ```c++ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 20; const int MAXM = 20; int n, m, sx, sy, ex, ey; char maze[MAXN][MAXM]; // 迷宫 int vis[MAXN][MAXM]; // 标记数组 int dx[] = {0, 0, 1, -1}; // 方向数组 int dy[] = {1, -1, 0, 0}; void dfs(int x, int y) { if (x == ex && y == ey) { // 到达终点 printf("(%d,%d)", x, y); return; } for (int i = 0; i < 4; i++) { // 依次尝试四个方向 int nx = x + dx[i]; int ny = y + dy[i]; if (nx >= 0 && nx < n && ny >= 0 && ny < m && maze[nx][ny] != '#' && !vis[nx][ny]) { vis[nx][ny] = 1; // 标记已访问 printf("(%d,%d)->", x, y); dfs(nx, ny); return; } } } int main() { while (scanf("%d%d", &n, &m) == 2) { memset(vis, 0, sizeof(vis)); for (int i = 0; i < n; i++) { scanf("%s", maze[i]); for (int j = 0; j < m; j++) { if (maze[i][j] == 'S') { sx = i; sy = j; } else if (maze[i][j] == 'T') { ex = i; ey = j; } } } vis[sx][sy] = 1; dfs(sx, sy); printf("\n"); } return 0; } ``` 代码实现中,使用了一个标记数组 `vis` 来标记每个位置是否已经被访问过,避免走重复的路线。使用DFS的时候,每次从当前位置依次尝试四个方向,如果某个方向可以走,则标记该位置已经被访问过,并输出当前位置的坐标,然后递归进入下一个位置。如果当前位置是终点,则直接输出并返回。 在输出路径的时候,由于是递归调用,所以输出的路径是反向的,需要将其反转过来,即从终点往起点遍历输出。 需要注意的是,题目中要求输出的路径是 `(x1,y1)->(x2,y2)->...->(xn,yn)` 的形式,每个坐标之间用 `->` 连接。所以在输出的时候需要特别处理第一个坐标和最后一个坐标的格式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值