【无标题】

> 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

@[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;

}

```

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值