# 图的存储、邻接表

## 例题：P5318 【深基18.例3】查找文献

#include<bits/stdc++.h>
using namespace std;
typedef struct node{
int st;
int en;
}node1;
vector<int>a[100010];//邻接表
int vis[100010]={0};//访问
void dfs(int x){
vis[x] = 1;
cout<<x<<' ';
for(int i = 0;i < a[x].size();i++){
int tem = a[x][i];
if(!vis[tem])
dfs(tem);
}
}
void bfs(int x){
vis[x] = 1;
queue<int>q;
q.push(x);
while(!q.empty()){
int cnt = q.size();
for(int i = 0;i < cnt;i++){
int tem = q.front();
q.pop();
cout<<tem<<' ';
for(int i = 0;i < a[tem].size();i++){
if(!vis[a[tem][i]]){
q.push(a[tem][i]);
vis[a[tem][i]] = 1;
}
}
}
}
}
int main(){
int n,m;//点数,边数
cin>>n>>m;
int Min = 100010;
for(int i = 0;i < m;i++){
int t1,t2;
cin>>t1>>t2;
a[t1].push_back(t2);
Min = min(Min,t1);//记录最小点
}
for(int i = 1;i <= n;i++)
sort(a[i].begin(),a[i].end());//排序
dfs(Min);//从最小点开始
cout<<endl;
memset(vis,0,sizeof(vis));//初始化
bfs(Min);
}


# 链式前向星

#include<bits/stdc++.h>
using namespace std;
int n,m,cnt;//n个点 m条边
struct Edge{
int to;//终点
int w;//权值
int next;//相同起点的上条边编号
}edge[1010];
void ini(){
for(int i = 0;i <= n;i++)
cnt = 0;
}
edge[cnt].to = v;
edge[cnt].w = w;
}
void dfs(){
for(int i = 1;i <= n;i++){//n个起点
cout<<"起点"<<i<<":"<<endl;
for(int j = head[i];j != -1;j = edge[j].next){
printf("%d %d %d\n",i,edge[j].to,edge[j].w);
}
}
}
int main(){
cin>>n>>m;
int u,v,w;
ini();
for(int i = 1;i <= m;i++){
cin>>u>>v>>w;
}
dfs();
return 0;
}


# 拓扑排序、BFS

## 例题：P1113 杂务

#include<bits/stdc++.h>
using namespace std;
int in[50010]={0};//保存入度
int ans[50010];//保存答案
int v[50010];//保存点权值
vector<int>a[10010];
queue<int>q;
void bfs(){
while(!q.empty()){
int tem = q.front();
q.pop();
for(int i = 0;i < a[tem].size();i++){
int u = a[tem][i];
in[u]--;
if(in[u] == 0)
q.push(u);
ans[u] = max(ans[u],ans[tem]+v[u]);
}
}
}
int main(){
int n;
cin>>n;
for(int i = 1;i <= n;i++){
int x;
cin>>x;
cin>>v[x];
int tem;
while(scanf("%d",&tem) && tem){
a[tem].push_back(x);
in[x]++;
}
}
for(int i = 1;i <= n;i++)
if(in[i] == 0){
q.push(i);
ans[i] = v[i];
}
bfs();
int Max = -10000;
for(int i = 1;i <= n;i++)
Max = max(ans[i],Max);
cout<<Max;
return 0;
}
/*
初始化队列，将入度为0的点放入队列，并初始化对应点的答案
取出队首，检查出边点，将它们的入度减一，通过DP转移公式维护答案
当某点入度变成0时将其加入至队列
重复第二第三步，直至队列为空

*/


# SPFA、最短路（输出字典序最小的最短路径）

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct Edge{
int to;//终点
int w;//权值
int next;//上一个相同起点的边的编号
}edge[10510];
int pre[10510]={0};
int len[10510];
int dis[15100];
bool vis[15100];
int cnt;
int n,m;
int cmp(int a,int b){
//cout<<a<<' '<<b<<endl;
if(a == 0)
return -1;
int tem = cmp(pre[a],pre[b]);
if(tem == -1){
if(a == b)
return -1;
else if(a < b)
return 1;
else
return 0;
}
else
return tem;

}
void ini(){
for(int i = 0;i <= n;i++)
cnt = 0;
memset(len,0x3f,sizeof(len));
}
edge[cnt].to = v;
edge[cnt].w = w;
}

int tp = 0;
int tp1 = 0;
int ans = 0;
int a[15100];
int top(){
return a[tp+1];
}
int empty(){
if(tp == tp1)
return 0;
else
return 1;
}
void push(int x){
a[++tp1] = x;
}
void pop(){
tp++;
}
void clear(){
tp = tp1 = 0;
}
int pop_back(){
tp1--;
return a[tp1+1];
}
void spfa(){
memset(vis,0,sizeof(vis));
for(int i = 0;i < 15100;i++){
dis[i] = 1000000010;
}
dis[0] = 0;
push(0);
vis[0] = 1;
while(empty()){
int u = top();
pop();
vis[u] = 0;
for(int i = head[u];~i;i = edge[i].next){
int v = edge[i].to;
if(dis[u] + edge[i].w < dis[v]){
dis[v] = dis[u] + edge[i].w;
len[v] = len[u] + 1;
if(!vis[v]){
push(v);
vis[v] = 1;
}
pre[v] = u;
}
else if(dis[u] + edge[i].w == dis[v] && len[u] + 1 < len[v]){
len[v] = len[u] + 1;
if(!vis[v]){
push(v);
vis[v] = 1;
}
pre[v] = u;
}
else if(dis[u] + edge[i].w == dis[v] && len[u] + 1 == len[v] && cmp(u,pre[v]) == 1){
pre[v] = u;
if(!vis[v]){
push(v);
vis[v] = 1;
}
}
}
}
}

int main(){
cin>>n>>m;
ini();
for(int i = 0;i < m;i++){
int u,v,w;
cin>>u>>v>>w;
pre[v] = u;
}
spfa();
for(int i = 1;i < n;i++){
clear();
if(dis[i] == 1000000010)
continue;
for(int j = i;j != 0;j = pre[j]){
//cout<<j<<' ';
push(j);
}
printf("0");
for(int i = tp1;i > tp;i--){
printf("->%d",pop_back());
}
cout<<endl;
}
return 0;

}
/*

7 8
0 2 1
0 1 1
2 3 1
1 4 1
1 5 1
3 6 1
4 6 1
5 6 1
*/


# BFS暴搜

#include<iostream>
#include<cstdio>
using namespace std;
int dir[4][2]={1,0,0,1,-1,0,0,-1};
int m[110][110];
int vis[110][110]={0};
int a1,b1;
int st1,st2;

struct node{
int x;
int y;
}a[10010];
int tp = 0;
int tp1 = 0;
int ans = 0;
void pop(){
//if(tp1 == tp){
//    cout<<"invalid"<<endl;
//    return;
//}
//cout<<a[tp + 1]<<endl;
tp++;
}
void push(int x,int y){
a[++tp1].x = x;
a[tp1].y = y;
}
int size(){
return tp1-tp;
}
int judge(int x,int y){
if(x >= 0 && y >= 0 && x < a1 && y < b1 && !vis[x][y] && (m[x][y] == 0 || m[x][y] == 4))
return 1;
else
return 0;
}
int empty(){
if(tp1 - tp == 0)
return 1;
else
return 0;
}
struct node top(){
return a[tp+1];
}
int flag = 0;
int bfs(int x,int y){
vis[x][y] = 1;
push(x,y);
while(!empty()){
int cnt = size();
for(int i = 0;i < cnt;i++){
struct node tem = top();
//cout<<tem.x<<' '<<tem.y<<endl;
if(m[tem.x][tem.y] == 4)
return 1;
pop();
for(int i = 0;i < 4;i++){
int t1 = tem.x + dir[i][0];
int t2 = tem.y + dir[i][1];
if(judge(t1,t2)){
push(t1,t2);
vis[t1][t2] = 1;
}
}
}
ans++;
}
flag = 1;
cout<<"unreachable";
return 0;
}
int main(){
cin>>a1>>b1;
for(int i = 0;i < a1;i++)
for(int j = 0;j < b1;j++){
cin>>m[i][j];
if(m[i][j] == 3){
st1 = i;
st2 = j;
}
}
if(bfs(st1,st2))
cout<<ans;
return 0;
}


# Kruskal、最小支撑树（并查集）

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e6 + 1;

int n, m;

struct node {
int u;
int v;
int w;
} e[maxn];

int fa[maxn], cnt, sum, num;
int flag = 0;
void add(int x, int y, int w) {
e[++ cnt].u = x;
e[cnt].v = y;
e[cnt].w = w;
}

int find(int x) {
return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);//路径压缩
}

void kruskal() {
for(int i = 1; i <= cnt; i ++) {
int x = find(e[i].u);
int y = find(e[i].v);
if(x == y) continue;
fa[x] = y;
sum += e[i].w;
if(++ num == n - 1) {
flag = 1;
break;
}
}
}
void swap(int &x,int &y) {
x = x^y;
y = x^y;
x = x^y;
}
void sort() {
for(int i = 0; i < cnt-1; i++)
for(int j = i + 1; j < cnt; j++) {
if(e[i].w > e[j].w) {
swap(e[i].u,e[j].u);
swap(e[i].v,e[j].v);
swap(e[i].w,e[j].w);
}
}
}
void ini() {
cnt = 0;
sum = 0;
flag = 0;
num = 0;
memset(fa,0,sizeof(fa));
}
int main() {
while(cin>>n>>m) {
ini();
for(int i = 1; i <= n; i ++)
fa[i] = i;
while(m --) {
int x, y, w;
cin>>x>>y>>w;
}
sort();
kruskal();
if(flag)
printf("%d\n",sum);
else {
cout<<"There is no minimum spanning tree."<<endl;
}
}
return 0;
}


01-14 8万+

10-17 381
10-31 263
03-31 101
11-06 168
08-01 825
12-13 124
11-06 63
06-24 148
10-02 120
04-21 407
03-19 1304
08-30 101
10-31 402