0x01 实验目的
掌握无向图的创建、遍历方法。
0x02 实验内容
- 创建图类,存储结构使用邻接矩阵。
- 输入图的节点数n(小于10个)、边数m,节点分别用1-n代表。
- 采用“起始节点,终止节点,权值”输入图的m条边,创建图。
- 输出从节点1开始的BFS广度遍历,在遍历过程中,如果从一个节点出发有多个可以选择的节点,则优先选择编号较小的节点。
- 输出从节点1开始的DFS深度遍历,在遍历过程中,如果从一个节点出发有多个可以选择的节点,则优先选择编号较小的节点。
- 输出从第1节点到最后一个节点(即第n个节点)最短路径的长度,如果没有路经,输出0。
0x03 实验过程分析
建立Class-graph
- node:点数
- edge:边数
- noEdge:无边的标识
- a:二维数组(指针形式的创建过程)二维数组的值代表权重
class graph {public:graph(int n, int e) {node = n;edge = e;a = new int *[n+1];for(int i = 1; i <= n; i++) {a[i] = new int[n+1];for(int j = 1; j <= n; j++) {a[i][j] = noEdge;}}}private:int node;int edge;int ** a;int noEdge = 0;
};
插入边操作
因为是无向图,所以边是相互的。
void insertEdge(int start, int end, int weight) {a[start][end] = weight;a[end][start] = weight;}
广度优先搜索
用队列,因为要求输出逗号,所以写的比较复杂。
void BFS(int v, int reach[], int label) {bool flag = false;queue<int> q;reach[v] = label;q.push(v);while(!q.empty()) {int w = q.front();q.pop();if(flag == false) {flag = true;cout<<w;} else cout<<","<<w;for(int i = 1; i <= node; i++) {if(a[w][i] != 0 && reach[i] != label) {q.push(i);reach[i] = label;}}}}
简化后:无输出。
- v:搜索的起点
- reach:存储该点是否到达过
- label:到达后的标记
void BFS(int v, int reach[], int label) {queue<int> q;reach[v] = label;q.push(v);while(!q.empty()) {int w = q.front();q.pop();for(int i = 1; i <= node; i++) {//当有这条边&没到达过才会将其入队if(a[w][i] != 0 && reach[i] != label) {q.push(i);reach[i] = label;}}}}
深度优先搜索
用堆栈,递归调用的思想。
void DFS(int v, int reach[], int label) {reach[v] = label;if(fl == false) {cout<<v;fl = true;} else {cout<<","<<v;}for(int i = 1; i <= node; i++) {if(a[v][i] != 0 && reach[i] != label) {DFS(i,reach,label);}}}
同样,简化后代码:
- v:搜索的起点
- reach:存储该点是否到达过
- label:到达后的标记
因为要求从小的数开始输出,所以没有“恢复”
void DFS(int v, int reach[], int label) {reach[v] = label;for(int i = 1; i <= node; i++) {if(a[v][i] != 0 && reach[i] != label) {DFS(i,reach,label);}}}
加上“恢复”:
void DFS(int v, int reach[], int label) {reach[v] = label;for(int i = 1; i <= node; i++) {if(a[v][i] != 0 && reach[i] != label) {DFS(i,reach,label);reach[i] = 0;}}}
最短路径(起点到终点)
我的思路是:
- 首先,用宽度优先搜索,判断是否能够到达终点(看是否被到达标记标记到),不能的话,直接return 0;
- 然后,用深度优先搜索(必须用带“恢复”的,因为此时我们要遍历全部的路径,求他们的权重比较,而不只是遵循该规则的路径 – 如果从一个节点出发有多个可以选择的节点,则优先选择编号较小的节点),寻找每一条从起点到终点的路径,然后比较它们的权重,取最小值,最后返回。
int pathLength(int start) {int reach[100] = {0};int rea[100] = {0};bfs(1,reach,2);if(reach[node] != 2) return 0;else {dfs(1,rea,2,0);return crr[0];}}void dfs(int v, int reach[], int label, int weight) {reach[1] = label;for(int i = 1; i <= node; i++) {if(a[v][i] != 0 && reach[i] != label) {weight += a[v][i];//到达终点就退出if(i == node) {//与之前的权重比较,小就保留,大就舍弃if(weight < crr[0]) crr[0] = weight;return;} else {reach[i] = label;dfs(i,reach,label,weight);reach[i] = 0;//一定要减掉,不仅要恢复标记,还要恢复权重,否则结果会偏大weight -= a[v][i];}}}}void bfs(int v, int reach[], int label) {queue<int> q;reach[v] = label;q.push(v);while(!q.empty()) {int w = q.front();q.pop();for(int i = 1; i <= node; i++) {if(a[w][i] != 0 && reach[i] != label) {q.push(i);reach[i] = label;}}}}
输入处理
输入全都是字符串,属实是绷不住了,处理麻烦死了 。
直接看下面完整代码叭。。
在这贴一组测试数据
输入
5,8
1,2,10
1,3,50
1,5,100
2,3,200
2,4,30
3,4,290
3,5,250
4,5,280
输出
1,2,3,5,4
1,2,3,4,5
100
0x04 完整代码
#include<bits/stdc++.h>
using namespace std;
const int M = 100;
int arr[M];
int brr[M];
int crr[M];
int path[M];
bool fl = false;
class graph {public:graph(int n, int e) {node = n;edge = e;a = new int *[n+1];for(int i = 1; i <= n; i++) {a[i] = new int[n+1];for(int j = 1; j <= n; j++) {a[i][j] = noEdge;}}}void insertEdge(int start, int end, int weight) {a[start][end] = weight;a[end][start] = weight;}void BFS(int v, int reach[], int label) {bool flag = false;queue<int> q;reach[v] = label;q.push(v);while(!q.empty()) {int w = q.front();q.pop();if(flag == false) {flag = true;cout<<w;} else cout<<","<<w;for(int i = 1; i <= node; i++) {if(a[w][i] != 0 && reach[i] != label) {q.push(i);reach[i] = label;}}}}void DFS(int v, int reach[], int label) {reach[v] = label;if(fl == false) {cout<<v;fl = true;} else {cout<<","<<v;}for(int i = 1; i <= node; i++) {if(a[v][i] != 0 && reach[i] != label) {DFS(i,reach,label);}}}int pathLength(int start) {int reach[100] = {0};int rea[100] = {0};bfs(1,reach,2);if(reach[node] != 2) return 0;else {dfs(1,rea,2,0);return crr[0];}}void dfs(int v, int reach[], int label, int weight) {reach[1] = label;for(int i = 1; i <= node; i++) {if(a[v][i] != 0 && reach[i] != label) {weight += a[v][i];if(i == node) {if(weight < crr[0]) crr[0] = weight;return;} else {reach[i] = label;dfs(i,reach,label,weight);reach[i] = 0;weight -= a[v][i];}}}}void bfs(int v, int reach[], int label) {queue<int> q;reach[v] = label;q.push(v);while(!q.empty()) {int w = q.front();q.pop();for(int i = 1; i <= node; i++) {if(a[w][i] != 0 && reach[i] != label) {q.push(i);reach[i] = label;}}}}private:int node;int edge;int ** a;int noEdge = 0;
};
int main() {cout<<"Input"<<endl;string n = "",m = "";string S;cin>>S;int temp;for(int i = 0; i < S.length(); i++) {if(S.at(i) == ',') {temp = i;break;}}for(int p = 0; p < temp; p++) {n += S.at(p);}for(int p = temp + 1; p < S.length(); p++) {m += S.at(p);}int num1 = stoi(n);int num2 = stoi(m); graph g(num1,num2);for(int i = 0; i < num2; i++) {string s;cin>>s;int fir = 0;int sec = 0;for(int j = 0; j < s.length(); j++) {if(s.at(j) == ',' && fir == 0) fir = j;else if(s.at(j) == ',' && fir != 0) {sec = j;break;}}string s1 = "";string s2 = "";string s3 = "";for(int p = 0; p < fir; p++) {s1 += s.at(p);}for(int q = fir + 1; q < sec; q++) {s2 += s.at(q);}for(int o = sec + 1; o < s.length(); o++) {s3 += s.at(o);}g.insertEdge(stoi(s1), stoi(s2), stoi(s3));}cout<<"Output"<<endl;g.BFS(1,arr,2);cout<<endl;g.DFS(1,brr,2);cout<<endl;//让第0组权重无限大,其他就都会比他小了(crr[0] = 10000000;int ans = g.pathLength(1);cout<<ans<<endl;cout<<"End";return 0;
}