6 条题解

  • 0
    @ 2026-9-22 23:28:24

    这题除了欧拉回路以外就是个并查集+dfs板子题,唯一难点是欧拉回路
    核心考点应该是建图,我们知道一个单词由首字母指向尾字母,这两个字母看作图的节点,把单词从首字母到尾字母的部分看作一条有向边,这样就构成了一个有向图
    对于一个有向图,每个节点有两个属性叫入度和出度,入度就是有几条边连进来了,出度就是有几条边从这里出去了,我们可以在建图的时候统计这两个数据
    然后是欧拉路径的概念
    欧拉路径类似于一笔画游戏
    对于欧拉通路,起点的出度比入度多1,终点的入度比出度多1,这样才能保证一笔画完
    对于欧拉回路,其实是特殊的欧拉通路,它的起点和终点是同一个点,这就导致他每个点入度出度都是一样,题目给出要找字典序最小的情况,那只能每个点都当起点试一下,择优输出

    #include<bits/stdc++.h>
    #define endl '\n'
    
    using namespace std;
    using ll=long long;
    //边
    struct edge{
      int u,v;
      string w;
    };
    //并查集
    //find
    int fd(int x,vector<int>& fa){
      if(fa[x]==x) return x;
      return fa[x]=fd(fa[x],fa);
    }
    //union
    void unions(int a,int b,vector<int>& fa){
      int ra=fd(a,fa);
      int rb=fd(b,fa);
      if(ra!=rb) fa[ra]=rb;
    }
    //dfs
    void dfs(int u,const vector<edge>& edges,vector<int> adj[26],vector<bool>& used,vector<string>& p){
      //结束条件:所有边都被访问过
      for(int i:adj[u]){
        if(used[i]) continue;//剪枝
        used[i]=true;//标记
        dfs(edges[i].v,edges,adj,used,p);
        p.emplace_back(edges[i].w);//回溯
      }
    }
    int main()
    {
      ios::sync_with_stdio(false);
      cin.tie(nullptr);
    
      int n;
      cin>>n;
      while(n--){
        //初始化
        int m;
        cin>>m;
        vector<edge> edges;
        vector<int> adj[26];
        vector<int> fa(26);
        for(int i=0;i<26;i++) fa[i]=i;
        int in[26]={0};
        int out[26]={0};
        bool hedge[26]={false};
        //建图
        for(int i=0;i<m;i++){
          string w;
          cin>>w;
          int u=w.front()-'a';
          int v=w.back()-'a';
          edges.emplace_back(edge{u,v,w});
          adj[u].emplace_back(i);
          ++out[u];
          ++in[v];
          hedge[u]=true;
          hedge[v]=true;
          unions(u,v,fa);
        }
        //连通性检查
        set<int> roots;
        for(int i=0;i<26;i++){
          if(hedge[i]) roots.insert(fd(i,fa));
        }
        if(roots.size()>1){
          cout<<"***"<<endl;
          continue;
        }
        //出入度检查
        int srt=-1,srtc=0,endc=0;
        bool ok=true;
        for(int i=0;i<26;i++){
          if(out[i]-in[i]==1){
            srt=i;
            ++srtc;
          }
          else if(in[i]-out[i]==1) ++endc;
          else if(in[i]!=out[i]){
            ok=false;
            break;
          }
        }
        if(!ok||srtc!=endc){
          cout<<"***"<<endl;
          continue;
        }
        bool iscrt=(srtc==0);//判断回路
        //字典序排序
        for(int i=0;i<26;i++){
          sort(adj[i].begin(),adj[i].end(),[&](int a,int b){
            return edges[a].w<edges[b].w;
          });
        }
        //dfs求欧拉通路/回路
        vector<string> ans;
        if(!iscrt){//通路
          vector<bool> used(m,false);
          dfs(srt,edges,adj,used,ans);
          reverse(ans.begin(),ans.end());
        }else{//回路
          for(int i=0;i<26;i++){
            if(adj[i].empty()) continue;
            vector<bool> used(m,false);
            vector<string> p;
            dfs(i,edges,adj,used,p);
            reverse(p.begin(),p.end());
            if(ans.empty()||p<ans) ans=p;
          }
        }
        bool valid=false;
        for(auto& i:ans){
          if(valid) cout<<".";
          cout<<i;
          valid=true;
        }
        cout<<endl;
      }
    }
    

    信息

    ID
    162
    时间
    3000ms
    内存
    128MiB
    难度
    10
    标签
    递交数
    212
    已通过
    19
    上传者