--打印路径
Floyd算法:
floyd算法是最基础的最短路径算法,因此优先讲解:(此篇将默认各位读者已了解相应算法原理, 故只解释打印路径的代码)
memset(path, 0, sizeof(path)); //初始化路径数组
SPFA算法:
spfa是单源最短路径的快速算法, 是迪杰斯特拉算法的优化(个人认为), 平时较为常见:
#include<stack>
#include<queue>
void spfa(int sta);
using namespace std;
int a[1000][1000];
int dist[1000]; //记录起点到i点的距离
int path[1000]; //记录路径, 存储间隔点, path[i]即为起点与i点的间隔点,无间隔点,则为0
bool vist[1000]; //标记点是否使用过
int n, m;
int main(void) {
cin >> n >> m; //假设n为点的个数, m为待输入路径数
memset(a, 0x3f, sizeof(a));
for(int i = 1; i <= m; i++) {
int sta, ed, len;
cin >> sta >> ed >> len;
if(len < a[sta][ed]) { //相同两点的路径取最小的
a[sta][ed] = len;
a[ed][sta] = len;
}
}
spfa(1);
stack<int> s;
while(path[n] != 0) {
s.push(n);
n = path[n];
}
s.push(1);
while(!s.empty() ){
cout << s.top() << endl;
s.pop();
}
}
void spfa(intsta) {
memset(dist, 0x3f, sizeof(dist)); //dist数组初始化为inf, 表示两点不连通
memset(vist, 0x3f, sizeof(vist)); //vist素组初始化为未标记
memset(path, 0, sizeof(path));
queue<int> q;
q.push(sta);
vist[sta] = 1;
dist[sta] = 0;
while(!q.empty()) {
int gap = q.front(); q.pop();
for(int j = 1; j <= n; j++) {
if(dist[j] >dist[gap] + a[gap][j]) {
dist[j] =dist[gap] + a[gap][j];
path[j] =gap
//path数组记录起点与j点的间隔点
if(!vist[j]) {
q.push(j);
vist[j] = 1;
}
}
}
}
}
BFS搜索:
bfs算法用于解决最优解问题, 此处只是打印最短的路径:
#include<iostream>
#include<queue>
#include<stack>
using namespace std;
int n, m;
struct Node {
int x, y;
} sta;
char a[100][100];
int vist[100][100];
void bfs(Node sta);
int path[100][100];
int main(void) {
cin >>n >> m; //n为行数, m为列数
for(int i = 0; i <n; i++) {
for(int j = 0; j <m; j++) {
cin >> a[i][j];
if(a[i][j] == 'S') { //记录起始点坐标
sta.x = i;
sta.y = j;
}
}
}
bfs(sta);
}
void bfs(Node sta) {
memset(vist, 0, sizeof(vist));
vist[sta.x][sta.y] = 1;
stack<Node> sa;
queue<Node> q;
q.push(sta);
while(!q.empty()) {
Node va;
va = q.front(); q.pop();
if(a[va.x][va.y] == 'E') {
Node tmp;
int x = va.x, y = va.y;
while(!(x == sta.x && y == sta.y)) { //回溯
tmp.x = x;
tmp.y = y;
sa.push(tmp);
x =path[tmp.x][tmp.y] / m;
y =path[tmp.x][tmp.y] % m;
}
sa.push(sta); //起点入栈
while(!sa.empty()) { //输出
tmp = sa.top();
cout << "(" << tmp.x << " " << tmp.y << ")" << endl;
sa.pop();
}
return;
}
intxx[] = {1, -1, 0, 0};
int yy[] = {0, 0, 1, -1};
for(int i = 0; i < 4; i++) {
Node vb;
vb.x = va.x + xx[i];
vb.y = va.y + yy[i];
if(vb.x >= 0 && vb.x < n&& vb.y >= 0&& vb.y < m&& !vist[vb.x][vb.y]&& a[vb.x][vb.y] != '#') {
q.push(vb);
vist[vb.x][vb.y] = 1;
path[vb.x][vb.y] = va.x * m + va.y; //记录该点的上一点
}
}
}
DFS搜索:
#include<iostream>
#include<stack>
using namespace std;
char a[100][100];
int vist[100][100];
struct Node {
int x, y;
} sta;
stack<Node> sa, sb;
int cnt = 0;
void dfs(Node sta);
int n, m;
int main(void) {
while(cin >> m >> n) { //m为行数, n为列数
memset(vist, 0, sizeof(vist));
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
cin >> a[i][j];
if(a[i][j] == 'S') {
sta.x = i;
sta.y = j;
}
}
}
sa.push(sta); //起点入栈并标记
vist[sta.x][sta.y] = 1;
dfs(sta);
}
}
void dfs(Node sta) {
if(a[sta.x][sta.y] == 'E') { //判断是否到达终点
while(!sa.empty()) {
Node temp = sa.top(); //到达终点, 由于栈中记录的点是反向的,故借助sb栈调整顺序输出
sb.push(temp);
sa.pop();
}
while(!sb.empty()) { //sa栈还要回溯, 故将sb中的元素还原回去
Node temp = sb.top();
cout << "(" << temp.x << " " << temp.y << ")" << endl;
sa.push(temp);
sb.pop();
}
}
int xx[] = {0, 0, 1, -1};
int yy[] = {1, -1, 0, 0};
Node vb;
for(int i = 0; i < 4; i++) {
vb.x = sta.x + xx[i];
vb.y = sta.y + yy[i];
if(sta.x >= 0&& sta.x < m&& sta.y >= 0&& sta.y < n&& !vist[vb.x][vb.y]&& a[vb.x][vb.y] != '#') {
vist[vb.x][vb.y] = 1;
sa.push(vb); //满足条件的点入栈, 加入路径
dfs(vb);
vist[vb.x][vb.y] = 0; //回溯, 使已标记的点变为未标记并出栈
sa.pop();
}
}
return;
}
01背包问题:
#include<iostream>
#include<cstring>
#include<stack>
#include<queue>
using namespace std;
int n, m;
struct Node {
int mrk, p, v;
} a[1005];
int dp[500][1005];
bool path[500][1005];
int main(void) {
memset(path, 0, sizeof(path));
while(cin >> n >> m) {
for(int i = 1; i <= n; i++) {
cin >> a[i].mrk >> a[i].p >> a[i].v; //输入标号, 价格, 价值
}
for(int i = 1; i <= n; i++) {
for(int j = 0; j <= m; j++) {
dp[i][j] =dp[i - 1][j];
if(j >= a[i].p) {
if(dp[i][j] <dp[i - 1][j - a[i].p] + a[i].v) {
dp[i][j] = dp[i - 1][j - a[i].p] + a[i].v;
path[i][j] = 1; //记录该资金下是否购买该物品
}
}
}
}
for(int i = n; i >= 1 && m > 0; i--) { //输出物品标号
if(path[i][m] == true) {
cout << a[i].mrk << endl;
m -= a[i].p;
}
}
}
}
总结:路径打印除对dfs 是递归回溯过程外, floyd,spfa, bfs, 01背包问题等均为同一方法,只是实现不尽相同, 掌握一种即可快速上手.