洛谷刷题笔记 其二 fufhaha 2025-02-09 2025-04-06 洛谷笔记2 1.邻接表 有关树类型的问题基本上都可以用邻接表来表示
当出现图的连续关系的时候,可以用一个数组adj[i] [i+1]来表示节点i的下面有的根节点
1 2 3 int adj[i+1 ][i]int adj_size[i+1 ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 int adj[9 ][8 ];int adj_size[9 ];for (int i=1 ;i<=9 ;++i){ int x,y; scanf ("%d,%d" ,&x,&y); adj[x][adj_size[x]++]=y; } 这里还要后续对每个节点进行排序 for (int i=1 ;i<=n;++i){ qsort(adj[i],adj_size[i];sizeof (int ),1 ); }
dfs在邻接表中的应用(dfs应用:一是标记搜索,二是回溯搜索 )
1 2 3 4 5 6 7 8 9 10 11 12 int visited[i+1 ]={0 };int dfs (int node) { visited[node]=1 ; printf ("%d" ,node); for (int i=0 ;i<adj_size[node];++i){ int next=adj[node][i]; if (!visited[node]){ dfs(next); } } }
bfs在邻接表中的应用:(注意,这下方的大规模的会超时,尽量使用链式向前星做法来搞,不然超时超空间)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 int visited[i+1 ]={0 };int bfs (int start) { int queue [10000 ]; int front=0 ,rear=0 ; queue [rear++]=start; visited[start]=1 ; while (front<rear){ int node=queue [front++]; printf ("%d" ,node); for (int i=0 ;i<adj_size[node];++i){ int next=adj[node][i]; if (!visited[node]){ queue [rear++]=next; } } } }
2.链式向前星邻接表:适用于大范围遍历 链式向前星不用排序,本身就是一个无序的图表示
如下图,这个链表是反过来的

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int head[max];int edge[max];int next[max];int cnt;inline void init () { for (int i=0 ;i<max;++i){ head[i]=next[i]=-1 ; } cnt=0 ; } inline void addedge (int u,int v) { edge[cnt]=v; next[cnt]=head[u]; head[u]=cnt++; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { int to; int next; }Edge; Edge edge[200010 ]; int cnt=0 ;int head[100010 ];void addadge (int u,int v) { edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } int main () { int n,m; scanf ("%d %d" ,&n,&m); memset (head,-1 ,sizeof (head)); for (int i=0 ;i<m;++i){ int u,v; scanf (" %d %d" ,&u,&v); addadge(v,u); } int *a=(int *)malloc ((n+1 )*sizeof (int )); int *vis=(int *)calloc (n+1 ,sizeof (int )); int *queue =(int *)malloc ((n+1 )*sizeof (int )); for (int i=n;i>=1 ;--i){ if (!vis[i]){ int front=0 ,rear=0 ; queue [rear++]=i; vis[i]=1 ; a[i]=i; while (front<rear){ int u=queue [front++]; for (int j=head[u];j!=-1 ;j=edge[j].next){ int v=edge[j].to; if (!vis[v]){ vis[v]=1 ; a[v]=i; queue [rear++]=v; } } } } } for (int i=1 ;i<=n;++i){ printf ("%d " ,a[i]); } free (vis); free (a); free (queue ); return 0 ; }
3.技巧:大量遍历图的时候 如果题目让我们求一个点出发所能达到的最大点,这样要我们履历每个点,数据一旦多了时间复杂度就非常大
不如等价为: 从最大的点开始 ,统计有哪些点能达到这个最大点
这时,就可以反向地来建边,反向建边推荐用链式向前星
4.技巧:inline内联提升效率 在大量调用一些简短的函数时,可以在前面加上inline,这样编译器就会直接把该函数的代码插入对应位置 ,提升运行效率,但是,递归这种不知道要递归几次的函数不行
5.技巧:图的最短路径问题: Dijkstra算法 运用于1点到各个点的最短距离问题
这里通常使用邻接表来存储图,因为不同于Floyd算法是两点之间,这个是一点到各个点,图内比较稀疏
例题:(这道题传统的dijkstra算法好像也做不了,要用到堆优化)
2.蓝桥王国 - 蓝桥云课
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
详细看10.堆优化
Floyd-Warshall算法 适用于任意两点之间的最短距离
就是在两点之间加上大于1的点作为中转,以求达到最少的路径
例题:(本题还在想)
3.蓝桥王国2 - 蓝桥云课
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
6.关于指针的认知澄清 1.结构体中
1 2 3 4 5 6 7 8 9 10 11 12 13 tpyedef struct { int a; int b; }node; node *s[100 ]; adj[0 ]=malloc (3 *sizeof (node));
2.函数参数中:
1 2 3 4 5 6 7 8 int max (int *a,int *b) int *a;int max (int **a)
7.技巧:堆优化(堆优化是解决大规模最短路径问题的必备技能) 这里建议每次用dijkstra算法的时候都先默认配合堆优化使用
堆优化,因为堆操作通常是按大或小的优先值进行操作的,所以有些方面可以优化程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 tpyedef struct { int id; long long dist; }node; node heap[100000 ]; int heap_size=0 ;void push (int id,long long dist) { head[head_size].id=id; head[head_size].dist=dist; int current=head_size++; while (current>0 ){ int parent=(current-1 )/2 ; if (head[current].dist<head[parent].dist){ node tmp=head[current]; head[current]=head[parent]; head[parent]=tmp; current=parent; } else { break ; } } } void pop () { node top=heap[0 ]; head[0 ]=head[head_size--]; int current=0 ; while (1 ){ int l=current*2 +1 ; int r=current*2 +2 ; int small=0 ; if (l<head_size && head[l].dist<head[small].dist){ small=l; } if (r<head_size && head[r].dist<head[small].dist){ small=r; } if (small!=current){ node tmp=heap[current]; heap[current]=heap[small]; heap[small]=tmp; current=small; } else { break ; } } return top; }
接下来是堆优化在dijkstra算法中的应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 #include <stdio.h> #include <stdlib.h> #include <limits.h> typedef struct { int v; long long w; } Edge; typedef struct { int u; long long dist; } Node; Edge *adj[300001 ]; int adj_size[300001 ] = {0 };long long dist[300001 ];int visited[300001 ] = {0 };void swap (Node *a, Node *b) { Node t = *a; *a = *b; *b = t; } void heapify (Node *heap, int size, int i) { int smallest = i; int l = 2 * i + 1 ; int r = 2 * i + 2 ; if (l < size && heap[l].dist < heap[smallest].dist) smallest = l; if (r < size && heap[r].dist < heap[smallest].dist) smallest = r; if (smallest != i) { swap(&heap[i], &heap[smallest]); heapify(heap, size, smallest); } } void push (Node *heap, int *size, Node node) { heap[(*size)++] = node; for (int i = (*size)/2 - 1 ; i >= 0 ; --i) heapify(heap, *size, i); } Node pop (Node *heap, int *size) { Node res = heap[0 ]; heap[0 ] = heap[--(*size)]; heapify(heap, *size, 0 ); return res; } int main () { int n, m; scanf ("%d %d" , &n, &m); for (int i = 0 ; i < m; ++i) { int u, v; long long w; scanf ("%d %d %lld" , &u, &v, &w); adj_size[u]++; adj[u] = realloc (adj[u], adj_size[u] * sizeof (Edge)); adj[u][adj_size[u]-1 ] = (Edge){v, w}; } for (int i = 1 ; i <= n; ++i) dist[i] = LLONG_MAX; dist[1 ] = 0 ; Node heap[m]; int heap_size = 0 ; push(heap, &heap_size, (Node){1 , 0 }); while (heap_size > 0 ) { Node node = pop(heap, &heap_size); int u = node.u; if (visited[u]) continue ; visited[u] = 1 ; for (int i = 0 ; i < adj_size[u]; ++i) { int v = adj[u][i].v; long long w = adj[u][i].w; if (dist[v] > dist[u] + w) { dist[v] = dist[u] + w; push(heap, &heap_size, (Node){v, dist[v]}); } } } for (int i = 1 ; i <= n; ++i) { if (dist[i] == LLONG_MAX) printf ("-1 " ); else printf ("%lld " , dist[i]); } for (int i = 1 ; i <= n; ++i) free (adj[i]); return 0 ; }
8.memset–string.h 1 2 3 int a[n];memset (a,-1 ,n);