题目描述:
链接:https://vjudge.net/problem/HDU-1116
大致意思就是给你几个单词,问是否全部首尾相连起来,很明显是一道欧拉路题。
思路分析
上面说到这道题是一道判断欧拉路,接着往下分析:由于每个单词具有方向性,因此这是一个有向图。那么,我们很容易就想到:把首字母和为字母作为节点,单词作为路径。接下来,就是将字母转化为数字,我这里采用的方法是以与字符‘a’之间的差值表示字母。
然后,判断连通性就和无向图一样,dfs或者并查集。
接下来判断是否形成欧拉路。我们要分两种情况:
第一种情况,它形成了欧拉回路,那么,每个点的入度和出度应该是相当的,这个情况可以加个特判出来。
第二种情况,如果没有形成欧拉回路,那么,它应该有两个特殊的点:一个点入度-初度=1,一个点出度-入度=1,其他的点出度和入度都是相等的。
根据这些判断就行了,还是比较基础一道题。
完整代码
DFS
#include <iostream>
#include <vector>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn=100010;
int in[maxn]={0};//
int out[maxn]={0};//
int vis[30];//
int e[30][30]={0};
void dfs(int tar)
{
vis[tar]=1;
for(int i=0;i<26;i++)
{
if(e[tar][i]&&!vis[i])
{
dfs(i);
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
memset(vis,0,sizeof(vis));
memset(e,0,sizeof(e));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
int n;
cin>>n;
for(int i=0;i<n;i++)
{
string t;
cin>>t;
int a=t[0]-'a';
int b=t[t.size()-1]-'a';
out[a]++;
in[b]++;
if(a!=b) e[a][b]=e[b][a]=1;
}
int flag=0;
int s=-1,e=-1;
for(int i=0;i<26;i++)
{
if(out[i]-in[i]==1)
{
if(s==-1)
{
s=i;
}
else
{
flag=1;
break;
}
}
if(in[i]-out[i]==1)
{
if(e==-1)
{
e=i;
}
else
{
flag=1;
break;
}
}
}
if(flag==1)
{
cout<<"The door cannot be opened."<<endl;
continue;
}
if(s==-1&&s==e)
{
int flag=0;
for(int i=0;i<26;i++)
{
if(in[i]!=0)
{
s=i;
break;
}
}
dfs(s);
for(int i=0;i<26;i++)
{
if(in[i]!=out[i])
{
flag=1;
break;
}
if(in[i]!=0||out[i]!=0)
{
if(vis[i]==0)
{
flag=1;
break;
}
}
}
if(flag) cout<<"The door cannot be opened."<<endl;
else cout<<"Ordering is possible."<<endl;
continue;
}
if(s==-1)
{
for(int i=0;i<26;i++)
{
if(in[i]+out[i]==3)
{
s=i;
break;
}
}
}
dfs(s);
int counter=0;
for(int i=0;i<26;i++)
{
if(in[i]==out[i]&&in[i]==0)
{
continue;
}
else
{
if(vis[i]!=1)
{
flag=1;
break;
}
if(in[i]!=out[i]&&fabs(in[i]-out[i])!=1)
{
flag=1;
break;
}
}
}
if(flag) cout<<"The door cannot be opened."<<endl;
else cout<<"Ordering is possible."<<endl;
}
return 0;
}
并查集
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
int s[30]={0};
int in[30]={0};
int out[30]={0};
int vis[30]={0};
int find(int x)
{
if(s[x]==x) return x;
int root=x;
while(s[root]!=root) root=s[root];
while(x!=root)
{
int t=s[x];
s[x]=root;
x=t;
}
return root;
}
void union_set(int a,int b)
{
int root1=find(a);
int root2=find(b);
if(root1==root2) return;
s[root1]=root2;
}
void init()
{
memset(vis,0,sizeof(vis));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(int i=0;i<=26;i++) s[i]=i;
}
int main()
{
int T;
cin>>T;
while(T--)
{
init();
int n;
cin>>n;
for(int i=0;i<n;i++)
{
string str;
cin>>str;
int a=str[0]-'a';
int b=str[str.length()-1]-'a';
union_set(a,b);
vis[a]=vis[b]=1;
in[b]++,out[a]++;
}
int flag=0;
int r;
for(int i=0;i<26;i++)
{
if(vis[i]==1)
{
r=find(i);
break;
}
}
for(int i=0;i<26;i++)
{
if(!vis[i])
{
continue;
}
else
{
if(find(i)!=r)
{
flag=1;
break;
}
}
}
if(flag==1)
{
cout<<"The door cannot be opened."<<endl;
continue;
}
int flag1=0,flag2=0;
for(int i=0;i<26;i++)
{
if(in[i]-out[i]==1)
{
if(!flag1) flag1=1;
else flag=1;
}
if(out[i]-in[i]==1)
{
if(!flag2) flag2=1;
else flag=1;
}
if(fabs(out[i]-in[i])>1)
{
flag=1;
break;
}
}
if(flag==1)
{
cout<<"The door cannot be opened."<<endl;
}
else cout<<"Ordering is possible."<<endl;
}
return 0;
}