> 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
@[TOC]( )
---
# 前言:存图的几种方法
这里我们主要掌握邻接矩阵、邻接表、链式前向星三种方法。
![在这里插入图片描述](https://img-blog.csdnimg.cn/26137bd1abc94e83999ab274e9fd1c28.png)
-------
---
# 一、图的深度和广度优先遍历
题目:[洛谷P5318](https://www.luogu.com.cn/problem/P5318#submit)
思路:建立有向图,再分别遍历输出。
```cpp
/*本题主要考察图的深度和广度优先两种遍历方法,这里用的是之前学的用动态数组vector来存储两个点之前的关系,没用到本周所教的邻接表的知识*/
#include<bits/stdc++.h>
using namespace std;
int m,n;
const int MAX=1000010;
vector<int>G[MAX];
bool vis[MAX];
void dfs(int now,int num)
{
vis[now]=1;
cout<<now<<" ";
if(num==n)return ;//全部点都被遍历过了,就结束
for(int i=0;i<G[now].size();i++)//从now点遍历它所连接的点
{
if(!vis[G[now][i]])//如果这个点没有被便利过,就继续便利
{
dfs(G[now][i],num++);
}
}
}
void bfs()
{
queue<int>q;
q.push(1);
vis[1]=1;
while(!q.empty())
{
int now=q.front();
cout<<now<<" ";
q.pop();
for(int i=0;i<G[now].size();i++ )
{
if(!vis[G[now][i]])
{
q.push(G[now][i]);
vis[G[now][i]]=1;
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
G[x].push_back(y);//构建有向图;
}
for(int i=1;i<=n;i++)
{
sort(G[i].begin(),G[i].end());//由于有多个文献时,需要按照从小到大的顺序排列,故用sort排序。
}
dfs(1,0);
cout<<endl;
memset(vis,false,sizeof(vis));//dfs完了之后一定要对访问数组进行初始化。
bfs();
cout<<endl;
system("pause");
return 0;
}
```
---
# 二、floyd模板
题目:[洛谷U80592](https://www.luogu.com.cn/problem/U80592)
思路:floyd模板题,重点在于理解floyd算法的思想。
```cpp
/*#include<bits/stdc++.h>
using namespace std;
const int MAX=10010;
long long wuqiong=0x3f3f3f3f;
struct edge
{
int end , val;//end表示终点,val表示该条边的权重。
};
vector <edge> node[MAX];//node[i]表示从i出发到end建立无向边,权重为val。
int m,n;
int sum[MAX][MAX];
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
node[x].push_back({y,z});
node[y].push_back({x,z});
}
for(int i=1;i<=n;i++)
{
sum[i][i]=0;
for(int j=0;j<node[i].size();j++)
{
sum[i][node[i][j].end]=node[i][j].val;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j||sum[i][j])continue;
else sum[i][j]=wuqiong;
}
}
for(int k=1;k<=n;++k)
{
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
sum[i][j]=min(sum[i][j],sum[i][k]+sum[k][j]);
}
}
}
for(int i=1;i<=n;++i)
{
int num=0;
for(int j=1;j<=n;++j)
{
num+=sum[i][j];
}
cout<<num<<endl;
}
system("pause");
return 0;
}*/
//这是之前邻接表建图做的,不知道哪里有问题,下面是之际直接用邻接矩阵存值做的,套的floyd模板。
#include <bits/stdc++.h>
using namespace std;
/*负无穷大为0xc0c0c0c0*/long long inf=0x3f3f3f3f,d[5001][5001];//d[i][j]表示从i到j的最短路径,分三种情况:1.到本身的距离为0 2.若i和j相连,则距离已知 3.若两点未连接,则距离为无穷大。
const long long mod=998244354;
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
d[i][j]=inf;
d[i][i]=0;
}
}
for(int i=1;i<=m;i++){
long long x,y,l;
cin >> x >> y >> l;
d[x][y]=min(l,d[x][y]);
d[y][x]=min(l,d[y][x]);
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);//floyd模板
for(int i=1;i<=n;i++){
int sum=0;
for(int j=1;j<=n;j++)
if(d[i][j] != inf)sum=(sum+d[i][j])%mod;
cout << sum << endl;
}
system("pause");
return 0;
}
```
---
# 三、单源最短路径
题目:[洛谷P4779](https://www.luogu.com.cn/problem/P4779)
思路:经典的dijkstra堆优化模板。
```cpp
// luogu-judger-enable-o2
#include<bits/stdc++.h>
const int MaxN = 100010, MaxM = 500010;
struct Edge
{
int to, val, next;
}Edge[MaxM]; // 链式前向星
int head[MaxN], dis[MaxN], num=0;
bool vis[MaxN];
int n, m, s;
inline void add_Edge( int u, int v, int d ) //加边操作
{
++num;
Edge[num].val = d; //赋权
Edge[num].to = v; // 这条边终点
Edge[num].next = head[u]; //下一条边的下标
head[u] = num;//设置第一条边为当前边
}
struct node
{
int val; //距离
int pos; //点的位置
node(){}
node(int p , int v)
{
pos=p;
val=v;
}
bool operator < (const node &a)const
{
return val > a.val;
}
//重载"<"
} ;//结构体 结点
inline void dijkstra(int start)
{
std::priority_queue<node>que;
/*for(int i = 1 ; i<=n ; ++i)
{
dis[i]=0x3f;
vis[i]=false;
}*/
dis[start]=0;
que.push( node(start,0) );
while(!que.empty())
{
node temp=que.top(); //优先队列首元素就是dist数组最小值
que.pop();
int mini=temp.pos; //最小值为首元素节点
if(vis[mini])
continue;
vis[mini]=true;
//判断最小值是否被找过,如果找过则跳过继续。
for(int i=head[mini] ; i ; i=Edge[i].next)//首尾相连更新距离
{
int to=Edge[i].to;
if(dis[to]>dis[mini]+Edge[i].val)
{
dis[to]=dis[mini]+Edge[i].val;
if(!vis[to])
{
que.push(node(to,dis[to]));
}
}
}
}
}
int main()
{
scanf( "%d%d%d", &n, &m, &s );
for(int i = 1; i <= n; ++i)dis[i] = 0x7fffffff;
for( register int i = 0; i < m; ++i )
{
register int u, v, d;
scanf( "%d%d%d", &u, &v, &d );
add_Edge( u, v, d );
}
dijkstra(1);
for( int i = 1; i <= n; i++ )
printf( "%d ", dis[i] );
return 0;
}
```