✨欢迎来到脑子不好的小菜鸟的文章✨
🎈创作不易,麻烦点点赞哦🎈
所属专栏:刷题_脑子不好的小菜鸟的博客-CSDN博客
我的主页:脑子不好的小菜鸟
文章特点:关键点和步骤讲解放在
代码相应位置
拓扑排序 / 家谱树
https://vjudge.net/contest/613618#problem/A
//拓扑排序:找到入度为0的点,将其写入答案,再删去其箭头,再继续找入度为0的点,循环往复
vector<int>edeg[101];
int n, deg[101] = { 0 };//入度
void init()//建图
{
cin >> n;
int i, val;
for (i = 1; i <= n; i++)
{
while (cin >> val && val != 0)
{
edeg[i].push_back(val);
deg[val]++;
}
}
}
void toposort()//拓扑排序
{
int i;
queue<int> que;
for (i = 1; i <= n; i++)
{
if (deg[i] == 0)
{
cout << i << ' ';
que.push(i);
}
}
while (!que.empty())
{
int t = que.front();
que.pop();
for (int i : edeg[t])
//相当于i表示edeg[t]的第一个元素,进行一次循环后就是第二个元素,循环往复
{
deg[i]--;
if (deg[i] == 0)
{
cout << i << ' ';
que.push(i);
//push的原因:可能i(也就是edeg[t])还有箭头指向其他的数,也就是后面辈分比它小的,要通过i来找比它辈分小的
}
}
}
}
int main()
{
init();//建图
toposort();//拓扑排序
return 0;
}
P3371 【模板】单源最短路径(弱化版)
https://www.luogu.com.cn/problem/P3371
///*法一:邻接矩阵*/
占的空间较多,时间复杂度较大,不适合
/*法二:结构体,堆优化*/
//要一个结构体,存一个点相关的东西(to, wei, next)(终点, 权值, 下一个儿子)
//cnt:结构体下标
//head[MAX]:head[i]:查找i点的第一个儿子
//pos:将被标记的值
//ans[MAX]:最短距离
//visit[MAX]:是否被标记过
//题解:https://www.luogu.com.cn/article/oswxjzrl
#include <iostream>#include <climits>
using namespace std;
const int MAX = 1e6;int cnt;//结构体下标int visit[MAX];//标记int n, m, s;int head[MAX];//存放儿子int ans[MAX];//放到起点的最短距离
struct EDGE
{
int wei;//权值
int to;//目的地
int next;//下一个儿子
}edge[MAX];
void add(int u, int v, int w){
cnt++;
edge[cnt].wei = w;
edge[cnt].to = v;
edge[cnt].next = head[u];//将下一个儿子记录
head[u] = cnt;//更新第一个儿子
}
int main(){
cin >> n >> m >> s;
int i;
//初始化ans
for (i = 1; i <= n; i++)
ans[i] = INT_MAX;
ans[s] = 0;
int u, v, w;
for (i = 1; i <= m; i++)
{
cin >> u >> v >> w;
add(u, v, w);
}
int pos = s;//初始化pos为s
while (visit[pos] == 0)
{
int minn = INT_MAX;//注意更新
visit[pos] = 1;//标记
//更新儿子的最短路径
for (i = head[pos]; i != 0; i = edge[i].next)
{
if (visit[edge[i].to] == 0 && ans[edge[i].to] > ans[pos] + edge[i].wei)
ans[edge[i].to] = ans[pos] + edge[i].wei;
}
//找最短路径
for (i = 1; i <= n; i++)
{
if (visit[i] == 0 && ans[i] < minn)
{
minn = ans[i];
pos = i;
}
}
}
for (i = 1; i <= n; i++)
cout << ans[i] << ' ';
cout << endl;
return 0;
}
P4779 【模板】单源最短路径(标准版)
https://www.luogu.com.cn/problem/P4779
注意:该题用上一题的代码会超时,因此要用堆优化,也就是优先队列
//友情提示:正权图 请 使用dijkstra算法, 负权图 请 使用SPFA算法
//弱化版的代码超时---->要用堆优化
/*
核心:priority_queue< pair<int,int> > 用优先队列来取最近的点,就不用遍历找点了
在pq中,是按pair的第一个元素(first)由大到小排序的,所以pair<距离,点号>,注意因为要的是最小值,所以距离要存负值
其实距离是纯纯的工具人,我们只是需要它来维持点的排序
每次取队首h,取出的就是dis最短的点
还要注意:
如果这个点的dis不等于h的dis,说明这个点在入队之后被更新了,那么我们就不用这个点了,直接continue;
因为后面会有个h2点比h1的dis更小,用h1更新就没有意义了
*/
//使用优先队列,注意:优先队列是从大到小排列,所以存进去应该存负数
C代码:
#include <queue>
/*堆优化:利用优先队列,降低复杂度,直接排序,注意优先队列是由大到小排列的,因此距离是负数 */
#include <climits>
#include <iostream>
using namespace std;
const int MAX = 1e6;
int n, m, s;
int ans[MAX];
int cnt;
int head[MAX];
int visit[MAX];
struct EDGE
{
int to;
int next;
int wei;
}edge[MAX];
void add(int u, int v, int w)
{
cnt++;
edge[cnt].wei = w;
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt;
}
int main()
{
int i;
int u, v, w;
cin >> n >> m >> s;
for (i = 1; i <= n; i++)
ans[i] = INT_MAX;
ans[s] = 0;
for (i = 1; i <= m; i++)
{
cin >> u >> v >> w;
add(u, v, w);
}
priority_queue<pair<int, int> >que;//距离,点
que.push({0, s});
while (!que.empty())
{
int qh = que.top().first;
int h = que.top().second;
que.pop();/*记得pop()!!!!!!!!!*/
if (visit[h] == 0)
{
visit[h] = 1;
for (i = head[h]; i != 0; i = edge[i].next)//不断找下一个儿子,直到找完
{
if (ans[edge[i].to] > ans[h] + edge[i].wei)
{
ans[edge[i].to] = ans[h] + edge[i].wei;
if (visit[edge[i].to] == 0)
que.push({ -ans[edge[i].to], edge[i].to });
}
}
}
}
for (i = 1; i <= n; i++)
cout << ans[i] << ' ';
cout << endl;
return 0;
}
B3647 【模板】Floyd
https://www.luogu.com.cn/problem/B3647
//floyd算法
//要注意中转点,可以直接i到j,也可以i->k,k->j,因此要比较两个数据的大小,最后表中的是最短路径
//注意是无向图
#include <climits>
int main()
{
int n, m, i, j, u, v, w;
long long board[105][105] = { 0 };//存最短路径
cin >> n >> m;
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
if (i == j)
board[i][j] = 0;
else
board[i][j] = INT_MAX;
}
}
for (i = 1; i <= m; i++)
{
cin >> u >> v >> w;
if (w < board[u][v])
board[u][v] = w;
if (w < board[v][u])
board[v][u] = w;
}
int k;
for (k = 1; k <= n; k++)//把k当中转点,注意是放在i,j循环的外面
{
for (i = 1; i <= n; i++)//行,列
{
if (i == k)
continue;
for (j = 1; j <= n; j++)
{
if (j == k)
continue;
if (i == j)
continue;
if (board[i][k] != INT_MAX && board[k][j] != INT_MAX)
board[i][j] = min(board[i][j], board[i][k] + board[k][j]);
}
}
}
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
cout << board[i][j] << ' ';
}
cout << endl;
}
return 0;
}
恭喜你啦,今天又进步了一点点~