单词游戏 题解
四倍经验
洛谷 SPOJ WORDS1 - Play on Words
题意
将 \(n\) 个单词,问能否把这些单词首尾相接的连起来(头尾字母要一样)。
分析
我们可以将每一个字母看成一个节点,这样我们就有了一个包含 26 个节点的图,对于读入的单词,我们将首字母和尾字母对应的节点之间建有向边(中间的字母没什么用就不管了)。
此时我们发现题目简化为:在一个有向图上,找到一条路径,使每条边都经过一次并且仅经过一次。
可以发现这正是欧拉路径问题,但是!你并不需要真的建图来跑一遍欧拉路径,只需对这张图判断是否存在欧拉路径即可。
欧拉路径的判定(有向图):除了起点和终点,每个点的入度等于出度。起点入度比出度小 1,终点入度比出度大 1。
注意判断图是否连通,用并查集就可以。
#include<bits/stdc++.h> using namespace std; #define ll long long int n; int t; int fa[100005];//为了并查集 int in[100005];//入度 int out[100005];//出度 int find(int x){//用并查集维护连通性 return (fa[x]==x)?x:find(fa[x]); } int main() { ios::sync_with_stdio(false); cin>>t; while(t--){ cin>>n; for(int i=0;i<26;i++){//初始化 in[i]=0; out[i]=0; fa[i]=i; } for(int i=1;i<=n;i++){ string s; cin>>s; int l=s[0]-'a';//首字母 int r=s[s.size()-1]-'a';//尾字母 fa[find(l)]=find(r);//连有向边 in[r]++;//入度增加 out[l]++;//出度增加 } int cnt=0; for(int i=0;i<26;i++){//判断连通性,判断是否存在不合法的节点 if(((out[i]||in[i])&&(find(i)==i))||abs(in[i]-out[i])>1){ cnt++; } } if(cnt>1){//不合法 cout<<"The door cannot be opened.\n"; continue; } int s=0;//起点数 int t=0;//终点数 for(int i=0;i<26;i++){ if(in[i]>out[i]){//终点数统计 t++; } if(in[i]<out[i]){//起点数统计 s++; } } if((s!=t)||t>1){//起点终点数都应该为 1 cout<<"The door cannot be opened.\n" ; continue; } cout<<"Ordering is possible.\n"; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」