教程来自代码随想录
1.1邻接矩阵储存法
//创建:二维数组
vector<vector<int>> graph(n,vector<int>(n,0));
//储存
for(int i=0;i<m;i++){
int x1,x2;
cin>>x1>>x2;
graph[x1-1][x2-1]=1;
}
1.2邻接表储存法
补充:c++中的list是链表 链接
//创建:数组+链表
vector<list<int>> graph(n + 1);
//输入
while (m--) {
cin >> s >> t;
// 使用邻接表 ,表示 s -> t 是相连的
graph[s].push_back(t);
}
//读取数据
if (result.size() == 0) cout << -1 << endl;
for (const vector<int> &pa : result) {
for (int i = 0; i < pa.size() - 1; i++) {
cout << pa[i] << " ";
}
cout << pa[pa.size() - 1] << endl;
}
2.1 dfs和bfs
所有可达路径
dfs三部曲:
确认递归函数和参数、确认终止条件、处理目前搜索节点的出发路径(处理节点、dfs递归、回溯)
#include<iostream>
#include<vector>
using namespace std;
vector<vector<int>> results;
vector<int> result;
//1 确认递归函数参数: 邻接表,当前历遍节点,终点
void dfs(const vector<vector<int>>& graph,int x,int n){
//2 确认终止条件:当当前节点x = 最后一个节点n,就是从起点到了终点
if(x==n-1){
results.push_back(result);//存入结果
return;
}
//3、处理目前搜索节点的出发路径
for(int i=0;i<n;i++){
if(graph[x][i]){ //找到下一个节点
result.push_back(i+1); //处理节点
dfs(graph,i,n); //处理下一个节点
result.pop_back(); //利用vector的性质回溯
}
}
}
int main(){
int n,m;
cin>>n>>m;
vector<vector<int>> graph(n,vector<int>(n,0));
for(int i=0;i<m;i++){
int x1,x2;
cin>>x1>>x2;
graph[x1-1][x2-1]=1;
}
result.push_back(1); //重要!先把开始节点放进去
dfs(graph,0,n);
if(results.size()==0)cout<<"-1"<<endl;
for(int i=0;i<int(results.size());i++){
for(int j=0;j<int(results[i].size()-1);j++){
cout<<results[i][j]<<" ";
}
cout<<results[i][results[i].size()-1]<<endl;
}
}
要注意0的问题。(开辟n个位置从0-n-1,开辟n+1个位置从0-n)
#include<iostream>
#include<vector>
#include<list>
using namespace std;
vector<vector<int>> results;
vector<int> result;
//1 确认递归函数参数: 邻接表,当前历遍节点,终点
void dfs(const vector<list<int>>& graph,int x,int n){
//2 确认终止条件:当当前节点x = 最后一个节点n,就是从起点到了终点
if(x==n-1){
results.push_back(result);//存入结果
return;
}
//3、处理目前搜索节点的出发路径
for(int i:graph[x]){ //找到下一个节点
result.push_back(i+1); //处理节点
dfs(graph,i,n); //处理下一个节点
result.pop_back(); //利用vector的性质回溯
}
}
int main(){
int n,m;
cin>>n>>m;
vector<list<int>> graph(n);
for(int i=0;i<m;i++){
int x1,x2;
cin>>x1>>x2;
graph[x1-1].push_back(x2-1);
}
result.push_back(1); //重要!先把开始节点放进去
dfs(graph,0,n);
if(results.size()==0)cout<<"-1"<<endl;
for(int i=0;i<int(results.size());i++){
for(int j=0;j<int(results[i].size()-1);j++){
cout<<results[i][j]<<" ";
}
cout<<results[i][results[i].size()-1]<<endl;
}
}
岛屿问题99
dfs
#include<iostream>
#include<vector>
using namespace std;
//1、确定参数
void dfs(const vector<vector<int>>& graph,vector<vector<int>>& visited, int x, int y){
int dir[4][2]={0,1, 1,0, -1,0, 0,-1};
//2、终止条件(访问过了/周边都是0了,一条路就走完了)
if(visited[x][y] || graph[x][y]==0) return;
//3、处理当前点
visited[x][y]=1;
for(int i=0;i<4;i++){//上下左右四个位置,作用是感染同一岛屿的所有块(颜色填充也是这个原理)
int newx=x+dir[i][0];
int newy=y+dir[i][1];
if(newx<0||newx>=int(graph.size())||newy<0||newy>=int(graph[0].size())) continue;
dfs(graph,visited,newx,newy);
}
}
int main(){
int n,m;
cin>>n>>m;
vector<vector<int>> graph(n,vector<int>(m,0));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>graph[i][j];
}
}
// for(int i=0;i<n;i++){
// for(int j=0;j<m;j++){
// cout<<graph[i][j]<<" ";
// }
// cout<<endl;
// }
vector<vector<int>> visited(n,vector<int>(m,0));
int result=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(!visited[i][j] && graph[i][j]==1){
dfs(graph,visited,i,j);
result++;
}
}
}
cout<<result;
}
bfs
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
void bfs(queue<pair<int,int>>& q,const vector<vector<int>>& graph,vector<vector<int>>& visited,int x,int y){
int dir[4][2]={0,-1, 0,1, -1,0, 1,0};
q.push({x,y});
visited[x][y]=1;//进队列就代表访问过了
while(!q.empty()){//队列+while(!q.empty()是bfs的精髓
pair<int,int> cur=q.front();//老天爷啊别忘了队列没有top
q.pop();
int curx=cur.first;
int cury=cur.second;
for(int i=0;i<4;i++){
int newx=curx+dir[i][0];
int newy=cury+dir[i][1];
//这里是用continue跳过!!不是break
if(newx<0||newx>=graph.size()||newy<0||newy>=graph[0].size()) continue;
if(!visited[newx][newy] && graph[newx][newy]==1){
q.push({newx,newy});
visited[newx][newy]=1;//进队列就代表访问过了。这两行要始终欧冠绑定在一起。
}
}
}
}
int main(){
int n,m;
cin>>n>>m;
vector<vector<int>> graph(n,vector<int>(m,0));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>graph[i][j];
}
}
// for(int i=0;i<n;i++){
// for(int j=0;j<m;j++){
// cout<<graph[i][j]<<" ";
// }
// cout<<endl;
// }
vector<vector<int>> visited(n,vector<int>(m,0));
queue<pair<int,int>> q;
int result=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(!visited[i][j] && graph[i][j]==1){
bfs(q,graph,visited,i,j);
result++;
//cout<<i<<" "<<j<<endl;
}
}
}
cout<<result;
}
岛屿最大面积100
bfs
#include<iostream>
#include<vector>
using namespace std;
//1、确定参数(注意!!这里visited和single想要被改变,要传入变量本身!要用&)
void dfs(const vector<vector<int>>& graph,vector<vector<int>>& visited,int x,int y,int& single){
//2、停止条件
if(graph[x][y]==0||visited[x][y]){return;}
//3、处理当前节点
single++;
visited[x][y]=1;
int dir[4][2]={0,-1,0,1,-1,0,1,0};
for(int i=0;i<4;i++){
int newx=x+dir[i][0];
int newy=y+dir[i][1];
if(newx<0||newx>=int(graph.size())||newy<0||newy>=int(graph[0].size())) continue;
dfs(graph,visited,newx,newy,single);
}
}
int main(){
int n,m;
cin>>n>>m;
vector<vector<int>> graph(n,vector<int>(m,0));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>graph[i][j];
}
}
int result=0;
vector<int> s;
vector<vector<int>> visited(n,vector<int>(m,0));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(!visited[i][j] && graph[i][j]==1){
int single=0;
dfs(graph,visited,i,j,single);
result=max(result,single);
}
}
}
cout<<result;
}
bfs
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
void dfs(const vector<vector<int>>& graph,vector<vector<int>>& visited,int x,int y,int& single){
queue<pair<int,int>> q;
int dir[4][2]={0,-1,0,1,-1,0,1,0};
if(graph[x][y]==0||visited[x][y]){return;}
q.push({x,y});
visited[x][y]=1;
single++;
while(!q.empty()){
pair<int,int> cur=q.front();
q.pop();
int curx=cur.first;
int cury=cur.second;
for(int i=0;i<4;i++){
int newx=curx+dir[i][0];
int newy=cury+dir[i][1];
if(newx<0||newx>=int(graph.size())||newy<0||newy>=int(graph[0].size())) continue;
if(!visited[newx][newy] && graph[newx][newy]==1){
q.push({newx,newy});
visited[newx][newy]=1;
single++;
}
}
}
}
int main(){
int n,m;
cin>>n>>m;
vector<vector<int>> graph(n,vector<int>(m,0));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>graph[i][j];
}
}
int result=0;
vector<int> s;
vector<vector<int>> visited(n,vector<int>(m,0));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(!visited[i][j] && graph[i][j]==1){
int single=0;
dfs(graph,visited,i,j,single);
result=max(result,single);
}
}
}
cout<<result;
}
孤岛总面积101
关键就是先历遍边缘,全部变成0.再处理中间的孤岛
dfs
#include<iostream>
#include<vector>
using namespace std;
//1、定参数
void dfs(vector<vector<int>>& graph,vector<vector<int>>& visited,int x,int y,int& count){
//2、终止条件
if(graph[x][y]==0)return;
count++;
//3、处理当前节点
graph[x][y]=0;//这里不一样,靠边的清零
int dir[4][2] = {-1, 0, 0, -1, 1, 0, 0, 1};
for (int i = 0; i < 4; i++) { // 向四个方向遍历
int nextx = x + dir[i][0];
int nexty = y + dir[i][1];
// 超过边界
if (nextx < 0 || nextx >= graph.size() || nexty < 0 || nexty >= graph[0].size()) continue;
if (!visited[nextx][nexty] && graph[nextx][nexty]){
dfs(graph,visited, nextx, nexty,count);
visited[nextx][nexty]=1;
graph[nextx][nexty]=0;
}
}
}
int main(){
int n,m;
cin>>n>>m;
int count=0;
vector<vector<int>> graph(n,vector<int>(m,0));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>graph[i][j];
}
}
vector<vector<int>> visited(n,vector<int>(m,0));
//先把有靠边的块清零(这里注意行列分开)
for(int i=0;i<n;i++){ //上限是n
if(graph[i][0]==1)dfs(graph,visited,i,0,count);
if(graph[i][m-1]==1)dfs(graph,visited,i,m-1,count);
}
for(int i=0;i<m;i++){ //上限是m
if(graph[0][i]==1)dfs(graph,visited,0,i,count);
if(graph[n-1][i]==1)dfs(graph,visited,n-1,i,count);
}
//---------------验证请完零没有----------------
// for(int i=0;i<n;i++){
// for(int j=0;j<m;j++){
// cout<<graph[i][j];
// }
// cout<<endl;
// }
//----------------------------------------------
// //再搜索
count=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(!visited[i][j]&&graph[i][j]==1){
dfs(graph,visited,i,j,count);
}
}
}
cout<<count;
}
bfs(两者计算面积的方式不一样!看count的计数)
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
void bfs(vector<vector<int>>& graph,vector<vector<int>>& visited,int x,int y,int& count){
queue<pair<int,int>> q;
int dir[4][2] = {-1, 0, 0, -1, 1, 0, 0, 1};
if(graph[x][y]==0)return;
q.push({x,y});
visited[x][y]=1;
graph[x][y]=0;//这里不一样,靠边的清零
count++;
while(!q.empty()){
pair<int,int> cur=q.front();
q.pop();
int curx=cur.first;
int cury=cur.second;
for (int i = 0; i < 4; i++) { // 向邻接的历遍
int nextx = curx + dir[i][0];
int nexty = cury + dir[i][1];
// 超过边界
if (nextx < 0 || nextx >= graph.size() || nexty < 0 || nexty >= graph[0].size()) continue;
if (!visited[nextx][nexty] && graph[nextx][nexty]){
q.push({nextx,nexty});
visited[nextx][nexty]=1;
graph[nextx][nexty]=0;
count++;
}
}
}
}
int main(){
int n,m;
cin>>n>>m;
int count=0;
vector<vector<int>> graph(n,vector<int>(m,0));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>graph[i][j];
}
}
vector<vector<int>> visited(n,vector<int>(m,0));
//先把有靠边的块清零(这里注意行列分开)
for(int i=0;i<n;i++){ //上限是n
if(graph[i][0]==1)dfs(graph,visited,i,0,count);
if(graph[i][m-1]==1)dfs(graph,visited,i,m-1,count);
}
for(int i=0;i<m;i++){ //上限是m
if(graph[0][i]==1)dfs(graph,visited,0,i,count);
if(graph[n-1][i]==1)dfs(graph,visited,n-1,i,count);
}
//---------------验证请完零没有----------------
// for(int i=0;i<n;i++){
// for(int j=0;j<m;j++){
// cout<<graph[i][j];
// }
// cout<<endl;
// }
//----------------------------------------------
// //再搜索
count=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(!visited[i][j]&&graph[i][j]==1){
dfs(graph,visited,i,j,count);
}
}
}
cout<<count;
}
#include<iostream>
#include<vector>
using namespace std;
//1、参数
void dfs(vector<vector<int>>& graph, vector<bool>& visited, vector<int>& start, vector<int>& end, int n, int& time,int node){
visited[node]=true;
start[node]=++time;
//3、处理节点
for(int to=1;to<=n;to++){
if(graph[node][to]&& !visited[to]){
dfs(graph,visited,start,end,n,time,to);
}
}
end[node] = ++time;
}
int main(){
int N;
cin>>N;
while(N--){
int n,m;
cin>>n>>m;
vector<vector<int>> graph(n+1,vector<int>(n+1,0));
for(int i=0;i<m;i++){
int x,y;
cin>>x>>y;
graph[x][y]=1;
graph[y][x]=1;
}
//检查用
// for(int i=1;i<=n;i++){
// for(int j=1;j<=n;j++){
// cout<<graph[i][j]<<" ";
// }
// cout<<endl;
// }
vector<bool> visited(n+1,false);
vector<int> start(n+1,0);
vector<int> end(n+1,0);
int time=0;
for(int node=1;node<=n;node++){
if(!visited[node])dfs(graph,visited,start,end,n,time,node);
}
for(int j=1;j<=n;j++){
cout<<j<<":"<<start[j]<<"-"<<end[j]<<endl;
}
cout<<"---"<<endl;
}
}
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
void dfs(const vector<vector<int>>& graph, vector<bool>& visited, int node, vector<int>& result) {
visited[node] = true;
result.push_back(node);
// 对邻居节点排序以确保按编号顺序访问
const vector<int>& neighbors = graph[node];
vector<int> sorted_neighbors(neighbors.begin(), neighbors.end());
sort(sorted_neighbors.begin(), sorted_neighbors.end());
for (int neighbor : sorted_neighbors) {
if (!visited[neighbor]) {
dfs(graph, visited, neighbor, result);
}
}
}
void bfs(const vector<vector<int>>& graph, vector<bool>& visited, vector<int>& result) {
queue<int> q;
q.push(1);
visited[1] = true;
while (!q.empty()) {
int current = q.front();
q.pop();
result.push_back(current);
// 对邻居节点排序以确保按编号顺序访问
const vector<int>& neighbors = graph[current];
vector<int> sorted_neighbors(neighbors.begin(), neighbors.end());
sort(sorted_neighbors.begin(), sorted_neighbors.end());
for (int neighbor : sorted_neighbors) {
if (!visited[neighbor]) {
visited[neighbor] = true;
q.push(neighbor);
}
}
}
}
int main() {
ios::sync_with_stdio(false); // 加快输入输出速度
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<vector<int>> graph(n + 1);
for (int i = 0; i < m; ++i) {
int u, v;
cin >> u >> v;
graph[u].push_back(v);
}
// DFS 遍历
vector<bool> visited_dfs(n + 1, false);
vector<int> dfs_result;
dfs(graph, visited_dfs, 1, dfs_result);
// 输出 DFS 结果
for (size_t i = 0; i < dfs_result.size(); ++i) {
cout << dfs_result[i];
if (i != dfs_result.size() - 1) cout << " ";
}
cout << endl;
// BFS 遍历
vector<bool> visited_bfs(n + 1, false);
vector<int> bfs_result;
bfs(graph, visited_bfs, bfs_result);
// 输出 BFS 结果
for (size_t i = 0; i < bfs_result.size(); ++i) {
cout << bfs_result[i];
if (i != bfs_result.size() - 1) cout << " ";
}
cout << endl;
return 0;
}
2.2 最小生成树
prim
#include<iostream>
#include <vector>
#include <climits>
using namespace std;
int main(){
int v,e;
cin>>v>>e;
vector<vector<int>> graph(v+1,vector<int>(v+1,100001));
while(e--){
int x1,x2,val;
cin>>x1>>x2>>val;
graph[x1][x2]=val;//是无向图
graph[x2][x1]=val;
}
//------------------检查用----------------------------
// for(int i=1;i<=v;i++){
// for(int j=1;j<=v;j++){
// cout<<graph[i][j]<<" ";
// }
// cout<<endl;
// }
//----------------------------------------------------
vector<int> minDist(v+1,100001);
vector<int> intree(v+1,false);
vector<int> arc(v+1);
int start=-1;
for(int count=1;count<v;count++){//循环n-1次
//1、选距离生成树最近的节点,即更新start
int min=INT_MAX;
for(int i=1;i<=v;i++){
if(!intree[i] && minDist[i]<min) {//这里是算生成树的每个节点与离它最近的树外节点的距离
min=minDist[i];
start=i;
}
}
if(start==-1) {cout<<"-1"<<endl;return 0;}
//把最近的节点加入生成树
intree[start]=1;
//------------------检查用----------------------------
// for(int i=1;i<=v;i++){
// cout<<minDist[i]<<" ";
// }
// cout<<"###################"<<endl;
//----------------------------------------------------
//3、更新非生成树节点到生成树的距离,即minDist数组。并记录1中最短边,即更新arc数组
for(int j=1;j<=v;j++){
if(!intree[j] && graph[start][j]<minDist[j]){//只要一端在start,另一端不在树里,且值比当前位置值小的,都放进来
minDist[j]=graph[start][j];
arc[j]=start;
}
}
//------------------检查用----------------------------
// for(int i=1;i<=v;i++){
// cout<<minDist[i]<<" ";
// }
// cout<<"-------------------"<<endl;
//----------------------------------------------------
}
int total=0;
for(int i=2;i<=v;i++){
total+=minDist[i];
}
cout<<total<<endl;
}
2.3 最短路径
如果是无向图的话,在graph输入的时候记住要同时输入graph[x][y]和graph[y][x]
主要是dijkstra算法
#include<iostream>
#include<vector>
#include<climits>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
vector<vector<int>> graph(n+1,vector<int>(n+1,INT_MAX));
for(int i=1;i<=m;i++){
int x,y,v;
cin>>x>>y>>v;
graph[x][y]=v;
//cout<<graph[x][y];
}
vector<int> minDist(n+1,INT_MAX);
vector<bool> visited(n+1,false);
int start=1;
int cur=start;
minDist[start]=0;
for(int i=0;i<n;i++){
int minVal=INT_MAX;
// 1、选距离源点最近且未访问过的节点
for(int j=1;j<=n;j++){
if(!visited[j] && minDist[j]<minVal){
minVal=minDist[j];
cur=j;
}
}
// 2、标记该节点已被访问
visited[cur]=true;
// 3、第三步,更新非访问节点到源点的距离(即更新minDist数组)
for(int j=1;j<=n;j++){
if(!visited[j] && graph[cur][j]!=INT_MAX && minDist[cur]+graph[cur][j]<minDist[j]){
minDist[j]=minDist[cur]+graph[cur][j];
}
}
// ---------------------打印日志检查----------------------------------
//cout << "select:" << cur << endl;
//for (int v = 1; v <= n; v++) cout << v << ":" << minDist[v] << " ";
//cout << endl << endl;;
}
int end=n;
if(minDist[end]==INT_MAX)cout<<"-1";
else cout<<minDist[end];
}
单源最短路径
#include<iostream>
#include<climits>
#include<vector>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
vector<vector<int>> graph(n+1,vector<int>(n+1,INT_MAX));
for(int i=0;i<m;i++){
int x,y,v;
cin>>x>>y>>v;
graph[x][y]=v;
//cout<<graph[x][y]<<endl;
}
vector<int> minDist(n+1,INT_MAX);
vector<bool> visited(n+1,false);
int start=1;
int cur=start;
minDist[start]=0;
for(int i=0;i<n;i++){
int minVal=INT_MAX;
//1、选距离源点最近且未访问过的节点
for(int j=1;j<=n;j++){
if(!visited[j] && minDist[j]<minVal){
minVal=minDist[j];
cur=j;
}
}
//2、标记选择的节点变为访问过
visited[cur]=true;
//3、更新minDist数组的值
for(int j=1;j<=n;j++){
if(!visited[j] && graph[cur][j]!=INT_MAX && minDist[cur]+graph[cur][j]<minDist[j]){
minDist[j]=minDist[cur]+graph[cur][j];//在选中的最短点(cur)的基础上计算最短路径,并更新更短的部分。
}
}
// //-------------------验证用--------------------------------
// cout<<"Current node: "<<cur<<endl;
// for(int j=1;j<=n;j++){
// cout<<minDist[j]<<" ";
// }
// cout<<endl;
}
//打印结果
for(int end=1;end<=n;end++){
if(minDist[end]==INT_MAX) cout<<"-1 ";
else cout<<minDist[end]<<" ";
}
}
全源最短路径
值得注意的是每次的minDist管一行用(即从start到1-n所有顶点)。
#include<iostream>
#include<vector>
#include<climits>
using namespace std;
int n,m;
//vector<vector<int>> graph;
void dijs(int start,vector<vector<int>> graph){
vector<int> minDist(n+1,INT_MAX);
vector<bool> visited(n+1,false);
minDist[start]=0;
int cur=start;
for(int i=1;i<=n;i++){
int minVal=INT_MAX;
//1、找到最小点
for(int j=1;j<=n;j++){
if(!visited[j] && minDist[j]<minVal){
minVal=minDist[j];
cur=j;
}
}
//2、标记该点被访问过
visited[cur]=true;
//3、更新minDist
for(int j=1;j<=n;j++){
if(!visited[j] && graph[cur][j]!=INT_MAX && minDist[cur]+graph[cur][j]<minDist[j]){
minDist[j]=minDist[cur]+graph[cur][j];
}
}
}
for(int end=1;end<=n;end++){
if(minDist[end]==INT_MAX) cout<<-1<<" ";
else cout<<minDist[end]<<" ";
}
}
int main(){
//int n,m;
cin>>n>>m;
//cout<<n<<m;
vector<vector<int>> graph(n+1,vector<int>(n+1,INT_MAX));
for(int i=0;i<m;i++){
int x,y,v;
cin>>x>>y>>v;
graph[x][y]=v;
//cout<<graph[x][y];
}
for(int start=1;start<=n;start++){
dijs(start,graph);
cout<<endl;
}
}
对于稀疏图,用最小堆
#include <iostream>
#include <vector>
#include <list>
#include <queue>
#include <climits>
using namespace std;
// 小顶堆
class mycomparison {
public:
bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
return lhs.second > rhs.second;
}
};
// 定义一个结构体来表示带权重的边
struct Edge {
int to; // 邻接顶点
int val; // 边的权重
Edge(int t, int w): to(t), val(w) {} // 构造函数
};
int main() {
int n, m, p1, p2, val;
cin >> n >> m;
vector<list<Edge>> grid(n + 1);
for(int i = 0; i < m; i++){
cin >> p1 >> p2 >> val;
// p1 指向 p2,权值为 val
grid[p1].push_back(Edge(p2, val));
}
int start = 1; // 起点
int end = n; // 终点
// 存储从源点到每个节点的最短距离
std::vector<int> minDist(n + 1, INT_MAX);
// 记录顶点是否被访问过
std::vector<bool> visited(n + 1, false);
// 优先队列中存放 pair<节点,源点到该节点的权值>
priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pq;
// 初始化队列,源点到源点的距离为0,所以初始为0
pq.push(pair<int, int>(start, 0));
minDist[start] = 0; // 起始点到自身的距离为0
while (!pq.empty()) {
// 1. 第一步,选源点到哪个节点近且该节点未被访问过 (通过优先级队列来实现)
// <节点, 源点到该节点的距离>
pair<int, int> cur = pq.top(); pq.pop();
if (visited[cur.first]) continue;
// 2. 第二步,该最近节点被标记访问过
visited[cur.first] = true;
// 3. 第三步,更新非访问节点到源点的距离(即更新minDist数组)
for (Edge edge : grid[cur.first]) { // 遍历 cur指向的节点,cur指向的节点为 edge
// cur指向的节点edge.to,这条边的权值为 edge.val
if (!visited[edge.to] && minDist[cur.first] + edge.val < minDist[edge.to]) { // 更新minDist
minDist[edge.to] = minDist[cur.first] + edge.val;
pq.push(pair<int, int>(edge.to, minDist[edge.to]));
}
}
}
if (minDist[end] == INT_MAX) cout << -1 << endl; // 不能到达终点
else cout << minDist[end] << endl; // 到达终点最短路径
}
2.4 拓扑排列
#include<iostream>
#include<vector>
#include<unordered_map>
#include<queue>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
vector<int> inDegree(n,0);
unordered_map<int,vector<int>> umap;//配对:每个顶点+该顶点关联的向量组
while(m--){
int s,t;
cin>>s>>t;
inDegree[t]++;
umap[s].push_back(t);
}
queue<int> q;//这个q是辅助工具
vector<int> result;
for(int i=0;i<n;i++){
if(inDegree[i]==0)q.push(i);
}
while(!q.empty()){
int cur=q.front();
q.pop();
result.push_back(cur);//1、入度为0的加入结果集
vector<int> v=umap[cur]; //找到该点对应的依赖节点串
if(!v.empty()){
for(int i=0;i<v.size();i++){
inDegree[v[i]]--;//2、从表中删除点。(形式上只是把入度-1
if(inDegree[v[i]]==0)q.push(v[i]);
}
}
}
if(result.size()==n){
for(int i=0;i<n-1;i++){
cout<<result[i]<<" ";
}
cout<<result[n-1];
}else{
cout<<"-1"<<endl;
}
}
#include<iostream>
#include<vector>
#include<queue>
#include <unordered_map>
using namespace std;
const int MOD = 80112002;
int main(){
int n,m;
cin>>n>>m;
vector<int> inDegree(n+1,0),outDegree(n + 1, 0);
unordered_map<int,vector<int>> umap;
queue<int> q;
vector<long long> pathCounts(n + 1, 0);//一个数组来存储到达每个节点的路径数量
for(int i=0;i<m;i++){
int u,v;
cin>>u>>v;
inDegree[v]++;
outDegree[u]++;
umap[u].push_back(v);
}
for(int i=1;i<=n;i++){
if(inDegree[i]==0) {
q.push(i);
pathCounts[i]=1;//初始化 每个开头都至少有一条
}
}
while(!q.empty()){
int cur=q.front();
q.pop();
//不需要排序结果
// for(int j=0;j<v.size();j++){
// inDegree[v[i]]--;
// if(inDegree[v[i]]==0)q.push(v[i]);
// }
//而是计算排序可能的种数
//先计算从每个点开始,到最终的种数
for (int next : umap[cur]) {
pathCounts[next] = (pathCounts[next] + pathCounts[cur]) % MOD;
if (--inDegree[next] == 0) {
q.push(next);
}
}
}
// 再计算所有消费者的和(即为最终解):将所有出度为0的节点(即消费者)的路径数量相加
long long result = 0;
for (int i = 1; i <= n; ++i) {
if (outDegree[i] == 0) { // 出度为0意味着是消费者
result = (result + pathCounts[i]) % MOD; //加和在这里
}
}
cout << result << endl;
}