图论基础问题【笔记】

本文主要介绍了图论的一些基础问题,包括图的遍历、欧拉路、无序字母对、词链、封锁阳光大学、信息传递、牛的野餐以及幻象迷宫等问题。通过洛谷平台的编程题目,详细讲解了每个问题的思路和解题方法,并提供了代码片段作为示例。
摘要由CSDN通过智能技术生成

主要集中一些初学图论的基础问题

第一题 洛谷P3916 图的遍历

题目描述

给出N个点,M条边的有向图,对于每个点v,求A(v)表示从点vv出发,能到达的编号最大的点。

sample input
4 3
1 2
2 4
4 3
sample output
4 4 3 4
思路

建图很简单,但是要到达最大的点,dfs每个点那么会T,最好的办法是反向存图,看最大的边可以到达哪些点并进行标记就行了

代码片
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;

#define MAXL 100010

int N, M, A[MAXL];
vector<int> G[MAXL]; //vector存图 

void dfs(int x, int d) //d保留最大值,x表示现在的结点
{
   
    if(A[x]) return; //访问过 
    A[x] = d;
    for(int i=0; i<G[x].size(); i++)
        dfs(G[x][i], d);
}

int main() 
{
   
    int u, v;
    scanf("%d%d", &N, &M);
    for(int i=1; i<=M; i++) {
   
        scanf("%d%d", &u, &v);
        G[v].push_back(u); //反向建边 
    }
    for(int i=N; i; i--) dfs(i, i); 
    for(int i=1; i<=N; i++) printf("%d ", A[i]);
    printf("\n");
    return 0;
}

关于欧拉路的题目放两道
证明欧拉路和欧拉回路:
奇点:度数为奇数的点
欧拉路:只有两个奇点连通的图在这里插入代码片
欧拉回路:没有奇点连通的图
求欧拉路:先判断奇点,再dfs
欧拉回路:对于任意一个点执行dfs
欧拉路:对奇点执行dfs

第二题 洛谷P1341 无序字母对

题目描述

给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。

输入格式

第一行输入一个正整数n。

以下n行每行两个字母,表示这两个字母需要相邻。

输出格式

输出满足要求的字符串。

如果没有满足要求的字符串,请输出“No Solution”。

如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案

sample input
4
aZ
tZ
Xt
aX
sample output
XaZtX
思路

本题其实问的是:给出一个无向图,求字典序最小的一条欧拉路径(自己可以画一个图就容易懂了)
注意点:
1、是否是连通图,用并查集判断,只有一个根
2、是否是欧拉路或者欧拉回路,判断奇点个数
3、dfs求欧拉路径

代码片(结合思路注释)

#include<bits/stdc++.h>
using namespace std;
//ascii不大于128,所以取130
const int N=52*51/2+10;    //每个字母可以和51个字母想连,所以字符个数为52*51/2
int f[130];   //并查集父结点,检查根的个数
int m[130][130],d[130];     //数据量不大,m为邻接矩阵,d记录度数
char ans[N];       //记录输出的字符串
int n;

void init() {
            //初始化
	for(int i=64; i<130; i++ ) f[i]=i;
	memset(m,0,sizeof(m));
	memset(d,0,sizeof(d));
}

int find(int x) {
          
	return x==f[x]?x:f[x]=find(f[x]);
}

void unions(int x, int y) {
   
	int fx=find(x);
	int fy=find(y);
	if ( fx!=fy ) f[fx]=fy;
}

void dfs(int head) {
             //路径搜索
	for(int i=64; i<130; i++ ) {
   
		if ( m[head][i] ) {
   
			m[head][i]=m[i][head]=0;
			dfs(i);
		}
	}
	ans[n--]=head;   //在回溯部分记录,因此需要倒序输出
}

int main() {
   
	char s[2];
	scanf("%d",&n);
	init();      //初始化
	for(int i=0
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值