图学习笔记

 1、邻接矩阵(vector二维数组)的DFS(递归实现)

class Graph {
public:
    Graph(int vertices);
    void addEdge(int from, int to);
    void DFS(int startVertex);

private:
    int vertices;
    vector<vector<int>> adjMatrix;
    vector<bool> visited;

    void DFSRecursive(int vertex);
};

Graph::Graph(int vertices) {
    this->vertices = vertices;
    adjMatrix.resize(vertices, vector<int>(vertices, 0));
    visited.assign(vertices, false);
}

// 无向图
void Graph::addEdge(int from, int to) {
    adjMatrix[from][to] = 1;
    adjMatrix[to][from] = 1; // For undirected graph
}

void Graph::DFS(int startVertex) {
    for (int i = 0; i < vertices; i++) {
        visited[i] = false;
    }
    DFSRecursive(startVertex);
    // 确保每一个点都能被遍历到,包括孤立点
    for (int i = 0; i < vertices; i++) {
        if(visited[i] == 0)    
            DFSRecursive(i);
    }
}

void Graph::DFSRecursive(int vertex) {
    visited[vertex] = true;
    cout << "Visited vertex: " << vertex << endl;

    for (int i = 0; i < vertices; i++) {
        if (adjMatrix[vertex][i] == 1 && !visited[i]) {
            DFSRecursive(i);
        }
    }
}

  2、邻接表(vector实现)的DFS(栈实现)

class Graph {
public:
    Graph(int vertices);
    void addEdge(int from, int to);
    void DFS(int startVertex);

private:
    int vertices;
    vector<vector<int>> adjList;
};

Graph::Graph(int vertices) {
    this->vertices = vertices;
    adjList.resize(vertices);
}

// 邻接表,每行长度不一。无向图
void Graph::addEdge(int from, int to) {
    adjList[from].push_back(to);
    adjList[to].push_back(from); 
}

void Graph::DFS(int startVertex) {
    vector<bool> visited(vertices, false);
    stack<int> s;

    visited[startVertex] = true;
    s.push(startVertex);


    while (!s.empty()) {
        int vertex = s.top();
        s.pop();
        cout << "Visited vertex: " << vertex << endl;

        for (int neighbor : adjList[vertex]) {
            if (!visited[neighbor]) {
                visited[neighbor] = true;
                s.push(neighbor);
            }
        }
    }
}

3、邻接表(vector实现)的BFS(队列实现)

class Graph {
public:
    Graph(int vertices);
    void addEdge(int from, int to);
    void BFS(int startVertex);

private:
    int vertices;
    vector<vector<int>> adjList;
};

Graph::Graph(int vertices) {
    this->vertices = vertices;
    adjList.resize(vertices);
}

// 无向图
void Graph::addEdge(int from, int to) {
    adjList[from].push_back(to);
    adjList[to].push_back(from);
}

void Graph::BFS(int startVertex) {
    vector<bool> visited(vertices, false);
    queue<int> q;

    visited[startVertex] = true;
    q.push(startVertex);

    while (!q.empty()) {
        int vertex = q.front();
        q.pop();
        cout << "Visited vertex: " << vertex << endl;

        for (int neighbor : adjList[vertex]) {
            if (!visited[neighbor]) {
                visited[neighbor] = true;
                q.push(neighbor);
            }
        }
    }
}

4、链式前向星DFS和BFS

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

const int maxn = 100000; // 假定最大顶点数

struct Edge {
    int to, w, next; // 终点,边权,同起点的上一条边的编号
} edge[maxn]; // 边集

int head[maxn]; // head[i],表示以i为起点的第一条边在边集数组的位置(编号)
int cnt = 0; // 记录边的数量
int n, m; // 顶点数和边数

void init() {
    for (int i = 1; i <= n; i++) head[i] = -1;
    cnt = 0;
}

// 添加新边
void add_edge(int u, int v, int w) {
    edge[cnt].to = v; // 终点
    edge[cnt].w = w; // 权值
    edge[cnt].next = head[u]; // 以u为起点上一条边的编号,也就是与这个边起点相同的上一条边的编号
    head[u] = cnt++; // 更新以u为起点上一条边的编号
}

void DFS(int startVertex) {
    vector<bool> visited(n + 1, false);
    stack<int> s;
    
    s.push(startVertex);
    visited[startVertex] = true;
    
    while (!s.empty()) {
        int vertex = s.top();
        s.pop();
        cout << "Visited vertex: " << vertex << endl;
        
        for (int j = head[vertex]; j != -1; j = edge[j].next) {
            int neighborVertex = edge[j].to;
            if (!visited[neighborVertex]) {
                s.push(neighborVertex);
                visited[neighborVertex] = true;
            }
        }
    }
}

void BFS(int startVertex) {
    vector<bool> visited(n + 1, false);
    queue<int> q;

    q.push(startVertex);
    visited[startVertex] = true;

    while (!q.empty()) {
        int vertex = q.front();
        q.pop();
        cout << "Visited vertex: " << vertex << endl;

        for (int j = head[vertex]; j != -1; j = edge[j].next) {
            int neighborVertex = edge[j].to;
            if (!visited[neighborVertex]) {
                q.push(neighborVertex);
                visited[neighborVertex] = true;
            }
        }
    }
}

int main() {
    cin >> n >> m;
    int u, v, w;
    init(); // 初始化
    for (int i = 1; i <= m; i++) // 输入m条边
    {
        cin >> u >> v >> w;
        add_edge(u, v, w); // 加边
    }

    int startVertex;
    cout << "Enter the starting vertex for DFS: ";
    cin >> startVertex;
    DFS(startVertex);

    cout << "Enter the starting vertex for BFS: ";
    cin >> startVertex;
    BFS(startVertex);

    return 0;
}

5、无向图中,DFS判断连通块数量

	void DFS() {
		vis.resize(vertices);
		vis.assign(vertices, 0);
		unlinked_part = 0;       // unlinked_part记录连通块数量

		for (int i = 0; i < vertices; i++) {
			if (vis[i] == 0) {
				DFSRecursive(i);
				unlinked_part++;
			}
		}
	}
	void DFSRecursive(int start) {
		vis[start] = 1;
		for (int i = 0; i < vertices; i++) {
			if (adjMatrix[start][i] == 1 && !vis[i]) {
				DFSRecursive(i);
			}
		}
	}

6、最小生成树

连通的带权无向图称为连通网。 最小生成树(Minimum Cost Spanning Tree)是代价最小的连通网的生成树,即该生成树上的边的权值和最小。
    
最小生成树的性质:
必须使用且仅使用连通网中的n-1条边来联结网络中的n个顶点;
不能使用产生回路的边;
各边上的权值的总和达到最小。
(1)Prim算法
class Graph {
	int vertices;
	vector<vector<int>> adjMatrix;
	map<string, int> ele1;
	map<int, string> ele2;
	vector<int> vis;
	struct Closeedge {
		int from;
		int lowcost;
	};

public:
	Graph() {}

	void build_Graph() {
		int n;
		cin >> n;
		this->vertices = n;
		adjMatrix.resize(vertices, vector<int>(vertices, INF));
		
		string* e = new string[n];
		for (int i = 0; i < n; i++) {
			cin >> e[i];
			ele1[e[i]] = i;  // 记录节点字符对应的下标
			ele2[i] = e[i];  // 记录下标对应的字符
		}
		int m;
		cin >> m;
		edgenum = m;
		for (int i = 0; i < m; i++) {
			string from, to;
			int value;
			cin >> from >> to >> value;
			addEdge(ele1[from], ele1[to], value);
		}
	}

	void addEdge(int from, int to,int value) {
		adjMatrix[from][to] = 1;
		adjMatrix[to][from] = 1;
	}


	int Min(vector<Closeedge> vec) {
		int k = -1, minn = INF;
		for (int i = 0; i < vertices; i++) {
			if (minn > vec[i].lowcost && vec[i].lowcost > 0) {
				minn = vec[i].lowcost;
				k = i;
			}
		}
		return k;
	}

	void Prim(string u) {
		int start = ele1[u];		 // start为起始节点的下标
		int totlowcost = 0;			 // 记录最小权值和
		vector<int> ans;			 // 记录被选节点
		map<int, int> ans_cost;		 // 记录最小生成树每条路径的权值
		vector<Closeedge> closeedge(vertices);  // 用于保存未选顶点的最小权值边closedge和这条边的另一个已选顶点

		for (int i = 0; i < vertices; i++) {
			closeedge[i] = { start, adjMatrix[start][i] };  // 初始化
		}

		closeedge[start].lowcost = 0;
		for (int i = 1; i < vertices; i++) {
			int k = Min(closeedge);    // 选择当前已选节点到未选节点最小权值边对应的未选节点
			totlowcost += closeedge[k].lowcost;
			ans.push_back(k);
			ans_cost[k] = closeedge[k].lowcost;
			closeedge[k].lowcost = 0;  // 已选顶点的最小权值边置0,后续将不再被选

			for (int j = 0; j < vertices; j++) {
				if (adjMatrix[k][j] < closeedge[j].lowcost) {
					closeedge[j] = Closeedge{ k, adjMatrix[k][j] };  // 更新未选顶点的最小权值边
				}
			}
		}

		cout << totlowcost << endl;
		for (int i = 0; i < vertices - 1; i++) {
			int k = ans[i];
			cout << ele2[closeedge[k].from] << " " << ele2[k] << " " << ans_cost[k] << endl;
		}
	}

};

(2)Kruscal算法

class MFSet {
	int n;
	vector<int> fa;
public:
	MFSet(int n) {
		this->n = n;
		fa.resize(n);
		for (int i = 0; i < n; i++)
			fa[i] = i;
	}
	int find(int k) {
		if (fa[k] != k) return fa[k] = find(fa[k]);
		else return k;
	}
	void concat(int i, int k) {
		fa[fa[i]] = fa[k];
		for (int i = 0; i < n; i++)
			find(i);
	}
	int check() {
		int che = fa[0];
		for (int i = 0; i < n; i++) {
			if (che != fa[i]) return 0;
		}
		return 1;
	}
};

class Graph {
	int vertices;
	int edgenum;
	vector<vector<int>> adjMatrix;
	map<string, int> ele1;
	map<int, string> ele2;
	vector<int> vis;

	struct edge {
		int from;
		int to;
	};

public:
	Graph() {}

	void build_Graph() {
		int n;
		cin >> n;
		this->vertices = n;
		adjMatrix.resize(vertices, vector<int>(vertices, INF));
		
		string* e = new string[n];
		for (int i = 0; i < n; i++) {
			cin >> e[i];
			ele1[e[i]] = i;  // 记录节点字符对应的下标
			ele2[i] = e[i];  // 记录下标对应的字符
		}
		int m;
		cin >> m;
		edgenum = m;
		for (int i = 0; i < m; i++) {
			string from, to;
			int value;
			cin >> from >> to >> value;
			addEdge(ele1[from], ele1[to], value);
		}
	}

	void addEdge(int from, int to,int value) {
		adjMatrix[from][to] = 1;
		adjMatrix[to][from] = 1;
	}

	void find_min(int &a, int &b, vector<vector<int>>& vis_adj) {
		int minn = INF;
		for (int i = 0; i < vertices; i++) {
			for (int j = i+1; j < vertices; j++) {
				if (minn > adjMatrix[i][j] && vis_adj[i][j] == 0) {
					minn = adjMatrix[i][j];
					a = i, b = j;
				}
			}
		}
		vis_adj[a][b] = 1;
	}
	void Kruscal(){
		vector<edge> ans;             // 记录最小生成树上的每条路径
		vector<vector<int>> vis_adj;  // 记录图中哪些边被选入最小生成树
		vis_adj.resize(vertices, vector<int>(vertices,0));
		MFSet mfset(vertices);        // 并查集,记录每个节点所在集合
		int totlowcost = 0;

		int t = edgenum;
		while (t--) {
			int u, v;
			find_min(u, v,vis_adj);   // 寻找未被选的最小权值边

			if (mfset.find(u) != mfset.find(v)) {  // 两个节点属于不同集合,该边选入最小生成树的路径中
				mfset.concat(u, v);
				ans.push_back({ u,v });
				totlowcost += adjMatrix[u][v];
			}
			
			if (mfset.check() == 1) break;   // 判断是否全部节点都属于同一集合,若是,则最小生成树已生成
		}
		if (mfset.check() == 0) {
			cout <<  -1 << endl;
		}
		else {
			cout << totlowcost << endl;
			for (int i = 0; i < ans.size(); i++) {
				cout << ele2[ans[i].from] << " " << ele2[ans[i].to] << " " << adjMatrix[ans[i].from][ans[i].to] << endl;
			}
		}
	}
	
};

7、无向图DFS生成森林

#include <iostream>
#include <vector>
#include <stack>
using namespace std;

// 树节点
struct treenode{
    int val;
    vector<treenode*> son; // 存儿子节点指针
    treenode(int n) { val = n; }
};

vector<treenode*> Root;  // 存每棵树的树根


class Graph {
public:
    Graph(int vertices);
    void addEdge(int from, int to);
    void DFS();
    treenode* DFSRecursive(int vertex);

private:
    int vertices;
    vector<vector<int>> adjMatrix;
    vector<bool> visited;
};

Graph::Graph(int vertices) {
    this->vertices = vertices;
    adjMatrix.resize(vertices, vector<int>(vertices, 0));
    visited.assign(vertices, false);
}

// 无向图
void Graph::addEdge(int from, int to) {
    adjMatrix[from][to] = 1;
    adjMatrix[to][from] = 1; 
}

void Graph::DFS() {
    visited.assign(vertices, 0);

    for (int i = 0; i < vertices; i++) {
        if (visited[i] == 0) {
            treenode* root;
            root=DFSRecursive(i);
            Root.push_back(root);
        }
    }
}

treenode* Graph::DFSRecursive(int vertex) {
    visited[vertex] = true;
    treenode* p = new treenode{ vertex };

    for (int i = 0; i < vertices; i++) {
        if (adjMatrix[vertex][i] == 1 && !visited[i]) {
            p->son.push_back(DFSRecursive(i));
        }
    }
    return p;
}

void show_tree(treenode *p) {
    cout << p->val;
    for (int i = 0; i < p->son.size(); i++) {
        if(p != nullptr)
            show_tree(p->son[i]);
    }
}

int main() {
    int n, m;
    cin >> n >> m;
    Graph G(n);
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        G.addEdge(u, v);
        G.addEdge(u, v);
    }
    G.DFS();
    
    for (int i = 0; i < Root.size(); i++) {
        show_tree(Root[i]);
        cout << endl;
    }
    return 0;
}

8、图的最短路径(迪杰斯特拉算法)

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;


class Graph {
	int vertices;
	vector<vector<int>> adjMatrix;
	map<string, int> ele1;
	map<int, string> ele2;
	vector<int> vis;

public:
	Graph() {}

	void build_Graph() {
		int n;
		cin >> n;
		this->vertices = n;
		adjMatrix.assign(vertices, vector<int>(vertices));

		string* e = new string[n];
		for (int i = 0; i < n; i++) {
			cin >> e[i];
			ele1[e[i]] = i;  // 记录节点字符对应的下标
			ele2[i] = e[i];  // 记录下标对应的字符
		}

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				int tmp;
				cin >> tmp;
				addEdge(i, j, tmp);
			}
		}
	}

	void addEdge(int from, int to, int value) {
		adjMatrix[from][to] = value;
	}

	void Dijkstra() {
		vector<queue<int>> path;   // 记录起点到其他每个节点最短路径的路径
		path.resize(vertices);
		vis.assign(vertices, 0);
		vector<int> dis;           // 记录起点到其他每个节点的最短路径距离
		dis.assign(vertices, INF);

		string start;
		cin >> start;
		int v = ele1[start];
		vis[v] = 1;
		dis[v] = 0;
		for (int i = 0; i < vertices; i++) {
			if(adjMatrix[v][i])
			{
				dis[i] = dis[v] + adjMatrix[v][i];   // 更新起点到其他点的最短路径距离
				path[i].push(v);
			}
		}

		for (int i = 0; i < vertices - 1; i++) {
			int Min = INF;
			for (int j = 0; j < vertices; j++)
				if (!vis[j] && Min > dis[j])
				{
					v = j;
					Min = dis[j];
				}
			vis[v] = 1;

			// 用当先被选中点来更新到最短路径距离
			for (int j = 0; j < vertices; j++) {
				if (!vis[j] && adjMatrix[v][j] && Min + adjMatrix[v][j] < dis[j]) {
					path[j] = path[v];
					path[j].push(v);
					dis[j] = Min + adjMatrix[v][j];
				}
			}
		}

		// 输出
		for (int i = 0; i < vertices; i++) {
			if (i != ele1[start]) {
				cout << start << "-" << ele2[i] << "-";
				if (dis[i] == INF) {
					cout << "-1" << endl;
				}
				else {
					cout << dis[i] << "----[";
					while(!path[i].empty()) {
						cout << ele2[path[i].front()] << " ";
						path[i].pop();
					}
					cout << ele2[i] << " ]" << endl;
				}
			}
		}

	}
};

int main() {
	int t;
	cin >> t;
	while (t--) {
		Graph G;
		G.build_Graph();
		G.Dijkstra();
	}
}

9、判断图上是否出现正环,即环上所有的边相乘大于1(货币套汇问题)

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;


class Graph {
	int vertices;
	vector<vector<double>> adjMatrix;
	map<string, int> ele1;
	map<int, string> ele2;
	vector<int> vis;
	vector<vector<double>> check; // check记录从i到j节点路径权值的乘积
	int flag;

public:
	Graph() {}

	void build_Graph() {
		int n;
		cin >> n;
		this->vertices = n;
		adjMatrix.assign(vertices, vector<double>(vertices, 0));
		int m;
		cin >> m;

		string* e = new string[n];
		for (int i = 0; i < n; i++) {
			cin >> e[i];
			ele1[e[i]] = i;  // 记录节点字符对应的下标
			ele2[i] = e[i];  // 记录下标对应的字符
		}

		for (int i = 0; i < m; i++) {
			string from, to;
			double value;
			cin >> from >> value >> to;
			addEdge(ele1[from], ele1[to], value);
		}

	}

	void addEdge(int from, int to, double value) {
		adjMatrix[from][to] = value;
	}


	int DFS() {
		vis.assign(vertices, 0);
		for (int i = 0; i < vertices; i++) {
			for (int j = 0; j < vertices; j++) {
				if (i == j) check[i][j] = 1;
				else check[i][j] = 0;
			}
		}
		flag = 0;

		for (int i = 0; i < vertices; i++) {
			if (vis[i] == 0)
				DFSRecursive(i);
			if (flag == 1) return 1;
		}
		return 0;
	}

	void DFSRecursive(int vertex) {
		vis[vertex] = true;

		for (int i = 0; i < vertices; i++) {

			// adjMatrix[vertex][i] && vis[i] == 1 即表示存在环,
			// check[i][vertex] * adjMatrix[vertex][i]即从i到j节点路径权值的乘积*j到i权值的乘积 = 环上权值乘积
			if (adjMatrix[vertex][i] && vis[i]) {  
				if (check[i][vertex] * adjMatrix[vertex][i] > 1) flag = 1;
				continue;
			}
			else if(adjMatrix[vertex][i]){
				for (int j = 0; j < vertices; j++) {
					check[j][i] = check[j][vertex] * adjMatrix[vertex][i];
				}
				DFSRecursive(i);
			}
		}
	}

};

int main() {
	int t;
	cin >> t;
	while (t--) {
		Graph G;
		G.build_Graph();
		if (G.DFS()) {
			cout << "YES" << endl;
		}
		else cout << "NO" << endl;
	}
}

10、键路径-STL版(含拓扑排序)

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;


class Graph {
	int vertices;
	vector<vector<int>> adjMatrix;
	vector<int> ve;    // 记录顶点的最早开始时间
	vector<int> vl;    // 记录顶点的最晚开始时间
	stack<int> st_re;  // 存AOE图的拓扑序列
	queue<int> q;      // 用于处理AOE图的拓扑序列
	vector<int> init;  // 记录节点入度

public:
	Graph() {}

	void build_Graph() {
		int n;
		cin >> n;
		this->vertices = n;
		adjMatrix.assign(vertices, vector<int>(vertices, 0));
		init.assign(vertices, 0);

		int m;
		cin >> m;
		for (int i = 0; i < m; i++) {
			int u, v, e;
			cin >> u >> v >> e;
			adjMatrix[u][v] = e;
			init[v]++;
		}
	}

	void Topoorder() {
		for (int i = 0; i < vertices; i++) {
			if (init[i] == 0) q.push(i);
		}
		
		ve.assign(vertices, 0);

		while (!q.empty()) {
			int w = q.front();
			st_re.push(w);
			q.pop();
			for (int i = 0; i < vertices; i++) {
				if (adjMatrix[w][i] != 0) {
					init[i]--;
					if (init[i] == 0) q.push(i);
					if (ve[w] + adjMatrix[w][i] > ve[i]) ve[i] = ve[w] + adjMatrix[w][i];
				}
			}
		}

		// 输出每个顶点的最早开始时间
		for (int i = 0; i < vertices; i++) {
			cout << ve[i] << " ";
		}
		cout << endl;

	}
	void CriticalPath() {
		vl.assign(vertices, ve[st_re.top()]); // ***注意:vl的初始化是用拓扑排序的最后一个顶点的ve值做初始化,而非
											  // 用ve[vertices - 1]做初始化,节点vertices - 1不一定为拓扑排序的最
											  // 后一个顶点,即不一定为AOE网的终点
		while (!st_re.empty()) {
			int w = st_re.top();
			st_re.pop();
			for (int i = 0; i < vertices; i++) {
				if (adjMatrix[i][w] != 0) {
					if (vl[w] - adjMatrix[i][w] < vl[i]) vl[i] = vl[w] - adjMatrix[i][w];
				}
			}
		}

		// 输出每个顶点的最迟开始时间
		for (int i = 0; i < vertices; i++) {
			cout << vl[i] << " ";
		}
		cout << endl;

		// 输出关键路径
		for (int i = 0; i < vertices; i++) {
			if (i == vertices - 1) cout << i << endl;
			if (ve[i] == vl[i] && i < vertices - 1) cout << i << "->";
		}
	}
};

int main() {
	Graph G;
	G.build_Graph();
	G.Topoorder();
	G.CriticalPath();
}

11、旅游规划

有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;


class Graph {
	int vertices;
	struct vec{
		int wag;
		int charge;
	};
	vector<vector<vec>> adjMatrix;
	vector<int> vis;
	int start, end;

public:
	Graph() {}

	void build_Graph() {
		int n;
		cin >> n;
		this->vertices = n;
		adjMatrix.assign(vertices, vector<vec>(vertices, {0,0}));

		int m;
		cin >> m;

		cin >> start >> end;

		for (int i = 0; i < m; i++) {
			int u, v, w, c;
			cin >> u >> v >> w >> c;
			addEdge(u, v, w, c);
		}
	}

	void addEdge(int from, int to, int w, int c) {
		adjMatrix[from][to].wag = w;
		adjMatrix[from][to].charge = c;
	}

	void Dijkstra() {
		vector<int> charge;
		charge.assign(vertices, 0);
		vis.assign(vertices, 0);
		vector<int> dis;
		dis.assign(vertices, INF);

		int v = start;
		vis[v] = 1;
		dis[v] = 0;
		charge[v] = 0;
		
		for (int i = 0; i < vertices; i++) {
			if(adjMatrix[v][i].wag)
			{
				dis[i] = dis[v] + adjMatrix[v][i].wag;
				charge[i] += adjMatrix[v][i].charge;
			}
		}

		for (int i = 0; i < vertices - 1; i++) {
			int Min = INF;
			for (int j = 0; j < vertices; j++)
				if (!vis[j] && Min > dis[j])
				{
					v = j;
					Min = dis[j];
				}
			vis[v] = 1;

			int tmpcharge;
			for (int j = 0; j < vertices; j++) {
				tmpcharge = INF;
				if (!vis[j] && adjMatrix[v][j].wag && Min + adjMatrix[v][j].wag <= dis[j]) {
					if (Min + adjMatrix[v][j].wag == dis[j] && charge[v] + adjMatrix[v][j].charge < tmpcharge) tmpcharge = charge[v] + adjMatrix[v][j].charge;
					dis[j] = Min + adjMatrix[v][j].wag;
				}
				if(tmpcharge != INF) charge[j] = tmpcharge;
			}
		}
		cout << dis[end] << " " << charge[end];
	}
};

int main() {
	
	Graph G;
	G.build_Graph();
	G.Dijkstra();
	
}

12、拯救007(坐标转为图节点)

将坐标轴上的点看作图的节点,将岸上坐标、鳄鱼坐标和岛上中心看作节点,看能否从岛上中心的节点遍历到岸上节点,若可,即可以逃脱

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
using namespace std;


class Graph {
	int vertices;
	vector<vector<int>> adjMatrix;
	struct Node {
		int x, y;
		Node() {}
		Node(int xx, int yy) { x = xx, y = yy; }
	};
	vector<int> vis;
	int D;
	vector<Node> node;
	int flag;

public:
	Graph() {}

	void build_Graph() {
		int n;
		cin >> n;
		this->vertices = n + 1;
		adjMatrix.assign(vertices + 1, vector<int>(vertices + 1, 0));
		cin >> D;

		for (int i = 0; i < n; i++) {
			int x, y;
			cin >> x >> y;
			node.push_back(Node{ x,y });
		}
		node.push_back(Node{ 0,0 });

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				if (i == j || distance(node[i], node[j]) > D) adjMatrix[i][j] = 0;
				else if (distance(node[i], node[j]) <= D) {
					adjMatrix[i][j] = 1;
					adjMatrix[j][i] = 1;
				}
			}
		}
		for (int i = 0; i < n; i++) {
			if (node[i].x*node[i].x + node[i].y * node[i].y  <= (7.5 + D)*(7.5 + D)) {
				adjMatrix[n][i] = 1;
			}
			else {
				adjMatrix[n][i] = 0;	
			}
		}
		adjMatrix[n][n] = 0;
	}

	double distance(Node a, Node b) {
		return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
	}

	void addEdge(int from, int to, int value) {
		adjMatrix[from][to] = value;
	}
	int check(Node p) {
		if (p.x - (-50) <= D || 50 - p.x <= D || p.y - (-50) <= D || 50 - p.y <= D) {
			return 1;
		}
		else return 0;
	}


	int DFS() {

		vis.assign(vertices, 0);
		flag = 0;

		
		for (int i = 0; i < vertices - 1; i++)
		{
			if (!vis[i] && adjMatrix[vertices - 1][i])  // 遍历图的起点只能从(0,0)开始
			{
				
				DFSRecursive(i);
			}
			if (flag == 1) return 1;
		}
		return 0;
	}

	void DFSRecursive(int vertex) {
		vis[vertex] = 1;
		if (check(node[vertex]) || flag == 1)
		{
			flag = 1; return;
		}
		for (int i = 0; i < vertices - 1; i++)
		{
			if (!vis[i] && adjMatrix[vertex][i])
			{
				DFSRecursive(i);
			}
		}

	}
};

int main() {
	Graph G;
	G.build_Graph();
	int check = G.DFS();
	if (check == 1) {

		printf("Yes\n");
	}
	else {
		printf("No\n");
	}
}

13、判断环

无向图:将图中度为1的顶点一个个删掉,同时把与该顶点相连的顶点度数减1,若图中仍存在度大于1的顶点,说明图中有环。

有向图:将图中入度为0的顶点一个个删掉,同时把与该顶点相连的顶点入度减1,若图中仍存在入读不为0的顶点,说明图中有环。

// 无向图判断环

#include<bits/stdc++.h>
#define MAXN 100010
using namespace std;

vector<vector<int>> vec;
int n;
vector<int> d;

int main()
{
    cin >> n;
    d.resize(n + 1, 0);
    vec.resize(n + 1);
    for (int i = 1; i <= n; i++) {
        int a, b;
        cin >> a >> b;
        d[a]++, d[b]++;
        vec[a].push_back(b);
        vec[b].push_back(a);
    }

    queue<int> q;
    for (int i = 1; i <= n; i++) {
        if (d[i] == 1) q.push(i);
    }
    while (!q.empty()) {
        int p = q.front();
        q.pop();
        for (int i = 0; i < vec[p].size(); i++) {
            --d[vec[p][i]];
            if (d[vec[p][i]] == 1) {
                q.push(vec[p][i]);
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        if (d[i] > 1) cout << i << " ";
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值