今天又来学习图论喵!
我们今天主要讲解一个东西:欧拉回路(路径)
什么是欧拉路径呢?
当然是指一笔画能把所有边都过一遍(包括重边)
而欧拉回路就是指起点和终点一样的回路
那么 我们怎么输出欧拉回路呢?
首先 我们要了解一个性质 在有向图里,如果存在欧拉路径 那么它存在有且仅有一个点出度比入度大一(起点),一个点入度比出度大一(终点),其他点入度和出度相等或者所有点入度等于出度(欧拉回路)
在无向图 就是直接度数为奇数的点就是起点
当然,存在欧拉回路的必要条件还有一个:图是连通的,不存在孤立的点
这个可以用并查集/DFS/以后学的tarjan缩点啥的判断
我们先看一下有向图欧拉路径的模版:
(通常会要求字典序最小,这个时候要排个序)最后用栈倒序输出
而且一般用邻接矩阵或者vector邻接表 链式前向星不好排序
洛谷P7771 欧拉路径
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m;
int x,y,sx=1;
int del[100005];
int snum,fnum;
vector<int>ver[100005];
stack<int>s;
int rd[100005],cd[100005];
void dfs(int x){for(int i=del[x];i<ver[x].size();i=del[x]){del[x]=i+1;dfs(ver[x][i]);}s.push(x);
}
int main(){scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){scanf("%d%d",&x,&y);rd[y]++;cd[x]++;ver[x].push_back(y);}for(int i=1;i<=n;i++) sort(ver[i].begin(),ver[i].end());bool flag=true;for(int i=1;i<=n;i++){if(rd[i]==cd[i]) continue;else{flag=false;if(rd[i]==cd[i]+1){fnum++;}else if(cd[i]==rd[i]+1){snum++;sx=i;}else{cout<<"No";system("pause");return 0;}}}if(!flag&&!(snum==1&&fnum==1)){cout<<"No";system("pause");return 0;} dfs(sx);while(!s.empty()){cout<<s.top()<<' ';s.pop();}system("pause");return 0;
}
然后再看一下无向图的:
洛谷P2731 骑马修栅栏
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int m,n;
int ma[505][505];
int d[505];
int x,y;
int st=505;
stack<int>s;
void dfs(int now){for(int i=1;i<=n;i++){if(ma[now][i]>=1){ma[now][i]--;ma[i][now]--;dfs(i);}}s.push(now);
}
int main(){scanf("%d",&m);for(int i=1;i<=m;i++){scanf("%d%d",&x,&y);n=max(n,max(x,y));st=min(st,min(x,y));ma[x][y]++;ma[y][x]++;d[x]++;d[y]++;}for(int i=1;i<=n;i++){if(d[i]%2){st=i;break;}}dfs(st);while(!s.empty()){cout<<s.top()<<endl;s.pop();}system("pause");return 0;
}
那么 进入我们今天的重点:A的第一道蓝题 词链!
看看题目:
P1127 词链
题目描述
如果单词 \(X\) 的末字母与单词 \(Y\) 的首字母相同,则 \(X\) 与 \(Y\) 可以相连成 \(X.Y\)。(注意:\(X\)、\(Y\) 之间是英文的句号 .
)。例如,单词 dog
与单词 gopher
,则 dog
与 gopher
可以相连成 dog.gopher
。
另外还有一些例子:
dog.gopher
gopher.rat
rat.tiger
aloha.aloha
arachnid.dog
连接成的词可以与其他单词相连,组成更长的词链,例如:
aloha.arachnid.dog.gopher.rat.tiger
注意到,.
两边的字母一定是相同的。
现在给你一些单词,请你找到字典序最小的词链,使得每个单词在词链中出现且仅出现一次。注意,相同的单词若出现了 \(k\) 次就需要输出 \(k\) 次。
输入格式
第一行是一个正整数 \(n\)(\(1 \le n \le 1000\)),代表单词数量。
接下来共有 \(n\) 行,每行是一个由 \(1\) 到 \(20\) 个小写字母组成的单词。
输出格式
只有一行,表示组成字典序最小的词链,若不存在则只输出三个星号 ***
。
输入输出样例 #1
输入 #1
6
aloha
arachnid
dog
gopher
rat
tiger
输出 #1
aloha.arachnid.dog.gopher.rat.tiger
说明/提示
- 对于 \(40\%\) 的数据,有 \(n \leq 10\);
- 对于 \(100\%\) 的数据,有 \(n \leq 1000\)。
解法&&个人感想:
看到欧拉回路已经有思想了
首先并查集判断连通性 找起点 然后终点输出
这题是n个 所以搜索带个数量 到n就输出
好了 就是我们的思想了:
把首尾字母视为边!而不是单词!然后用结构体存边(单词)
首先 如果是单词你不好处理像单词只有一个字母的情况
而且 如果是3 w w w这样的极端样例也不好处理
而这点我也是参考其他大佬的解法才看出来的
唉 还是比较菜
下面 我们开始吧!
#include<bits/stdc++.h>
#define ll long long
using namespace std;
string s[1005];
int n;
int fa[27];
int rd[27];
int cd[27];
int sx,fx;
int sum;
struct node{int to;int num;string a;
};
vector<node>ver[1005];
int cnt=0;
int st[1005];
int exist[27];
int del[27];
string res[1005];
int total_u;
int vis[1005];
int get(int x){if(fa[x]==x) return x;return fa[x]=get(fa[x]);
}
void merge(int x,int y){fa[get(x)]=get(y);return ;
}
void dfs(int now,int num,int count){if(count==n){for(int i=1;i<=sum;i++){if(i!=1) cout<<'.';cout<<res[i];}system("pause");exit(0);}for(int i=0;i<ver[now].size();i++){if(vis[ver[now][i].num]) continue;else{res[++sum]=ver[now][i].a;vis[ver[now][i].num]=1;dfs(ver[now][i].to,ver[now][i].num,count+1);sum--;vis[ver[now][i].num]=0;}//记得回溯}return ;
}
int main(){scanf("%d\n",&n);for(int i=1;i<=n;i++){cin>>s[i];}sort(s+1,s+1+n);for(int i=1;i<=n;i++){int s_begin=s[i][0]-'a'+1;int s_end=s[i][s[i].length()-1]-'a'+1;rd[s_end]++;cd[s_begin]++;if(!exist[s_begin]){//记录这个字母是否出现过fa[s_begin]=s_begin;total_u++;exist[s_begin]=1;}if(!exist[s_end]){fa[s_end]=s_end;total_u++;exist[s_end]=1;}if(s_begin!=s_end){//如果不是自环就连接if(get(s_begin)!=get(s_end)){merge(s_begin,s_end);total_u--;}}node tem;tem.to=s_end;tem.num=i;tem.a=s[i];ver[s_begin].push_back(tem);//建图}int ssum=0,fsum=0;for(int i=1;i<=26;i++){if(!exist[i]) continue;else if(rd[i]==cd[i]) continue;else if(rd[i]==cd[i]+1){fsum++;fx=i;}else if(rd[i]+1==cd[i]){sx=i;ssum++;}else{printf("***");system("pause");return 0;}}if(total_u!=1){printf("***");system("pause");return 0;}if(!((ssum==0&&fsum==0)||(ssum==1&&fsum==1))){printf("***");system("pause");return 0;}if(ssum==0&&fsum==0){sx=s[1][0]-'a'+1;}dfs(sx,0,0);system("pause");return 0;
}