图论基础例题及模板

图的存储、邻接表

例题: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];
int head[1010];//存储以i为起点的最后边的编号 
void ini(){
	for(int i = 0;i <= n;i++)
		head[i] = -1;//-1表示前面没有相同起点的边
	cnt = 0; 
} 
void add_edge(int u,int v,int w){//起点,终点,权值 
	edge[cnt].to = v;
	edge[cnt].w = w;
	edge[cnt].next = head[u];
	head[u] = cnt++;
}
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;
		add_edge(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时将其加入至队列
	重复第二第三步,直至队列为空
	 
*/

对于DP中为什么取最大值:在BFS的每一层中的杂务是同时进行的,所以可得一次的完成任务的消耗时间是该层的最大权值。需要的总时间即为每层的最大时间之和,即为答案ans[i]数组里的最大值。

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 head[15100];//存储以i为起点的最后条边的编号 
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++)
		head[i] = -1;
	cnt = 0;
	memset(len,0x3f,sizeof(len));
}
void addedge(int u,int v,int w){
	edge[cnt].to = v;
	edge[cnt].w = w;
	edge[cnt].next = head[u];
	head[u] = cnt++;
}

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;
		addedge(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;
			add(x, y, w);
		}
		sort();
		kruskal();
		if(flag)
			printf("%d\n",sum);
		else {
			cout<<"There is no minimum spanning tree."<<endl;
		}
	}
	return 0;
}
已标记关键词 清除标记
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符 “速评一下”
©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页