【洛谷P1127】词链
今天又来学习图论喵!
我们今天主要讲解一个东西:欧拉回路(路径)
什么是欧拉路径呢?
当然是指一笔画能把所有边都过一遍(包括重边)
而欧拉回路就是指起点和终点一样的回路
那么 我们怎么输出欧拉回路呢?
首先 我们要了解一个性质 在有向图里,如果存在欧拉路径 那么它存在有且仅有一个点出度比入度大一(起点),一个点入度比出度大一(终点),其他点入度和出度相等或者所有点入度等于出度(欧拉回路)
在无向图 就是直接度数为奇数的点就是起点
当然,存在欧拉回路的必要条件还有一个:图是连通的,不存在孤立的点
这个可以用并查集/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.gophergopher.ratrat.tigeraloha.alohaarachnid.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;
}

浙公网安备 33010602011771号