主要集中一些初学图论的基础问题
第一题 洛谷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