D168 欧拉路径 P1341 无序字母对

D168 欧拉路径 P1341 无序字母对_哔哩哔哩_bilibili

 

P1341 无序字母对 - 洛谷

给定 n 个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。构造一个有 (n+1) 个字母的字符串使得每个字母对都在这个字符串中出现

思路

类似 P1127 词链 - 洛谷 这道题,以字母对为边,因为是无序字母对,所以连无向边,例如,aX 就在 a 与 X 之间连无向边

建图后,每个单词只有两个字母,对字母按邻接点字母排序

先判断是否存在欧拉路,再 DFS 寻找字典序最小的欧拉路

注意:开个 g[x][y] 数组记录边的存在性,方便删除无向边

如图,对 aX,bX,cX,aY,bY,cY 建图排序,构造的字符串就是字典序最小的欧拉路径 XaYbXcY

参考:D165【模板】有向图 欧拉路径 欧拉回路 P7771 欧拉路径 - 董晓 - 博客园

 

// 欧拉路径 O(nlogn)
#include<bits/stdc++.h>
using namespace std;

int n,du[52];
int g[52][52];
vector<int> path;
vector<vector<int>> e(52); //邻接表
int p[52]; //p[x]表示点x当前处理到第几条出边,初始值为0,相当于全局指针

void dfs(int x){
  for(int i=p[x]; i<e[x].size(); i=p[x]){
    p[x]=i+1; //指向下一条边
    int y=e[x][i];
    if(g[x][y]){
      g[x][y]--; g[y][x]--; //删除正反边
      dfs(y);
    }
  }
  path.push_back(x);
}
int main(){
  ios::sync_with_stdio(0);cin.tie(0);
  cin>>n;
  for(int i=1,a,b;i<=n;i++){
    string s; cin>>s;
    if(s[0]>='A' && s[0]<='Z') a=s[0]-'A';
    else a=s[0]-'a'+26;
    if(s[1]>='A' && s[1]<='Z') b=s[1]-'A';
    else b=s[1]-'a'+26;
    e[a].push_back(b); 
    e[b].push_back(a); //无向边
    g[a][b]++; g[b][a]++;
    du[a]++; du[b]++;
  }

  for(int i=0; i<52; i++)if(!e[i].empty())
    sort(e[i].begin(),e[i].end()); //按邻接点排序
  
  int start=53,cnt=0;
  for(int i=0; i<52; i++)if(du[i]&1){ //如果度为奇数
    start=min(start,i);
    cnt++;
  }
  if(!(cnt==0||cnt==2)) //如果奇点数非0非2,则无解
    return cout<<"No Solution\n",0;
  
  if(start==53)for(int i=0; i<52; i++)
    if(du[i]){start=i; break;} //找出环的起点
    
  dfs(start);
  
  if(path.size()-1!=n) //如果不连通,则无解
    return cout<<"No Solution\n",0;
  
  reverse(path.begin(),path.end());
  for(auto i:path){
    if(i>=0 && i<26) cout<<(char)(i+'A');
    else cout<<(char)(i-26+'a');
  }
}

 

参考:D164【模板】无向图 欧拉路径 欧拉回路 P2731 [USACO3.3] 骑马修栅栏 - 董晓 - 博客园

// 欧拉路径 O(52^2)
#include<bits/stdc++.h>
using namespace std;

int n,du[52];
int g[52][52]; //邻接矩阵
vector<int> path;

void dfs(int x){
  for(int i=0; i<52; i++){
    if(g[x][i]){
      g[x][i]--; g[i][x]--; //删除正反边
      dfs(i);
    }
  }
  path.push_back(x);
}
int main(){
  ios::sync_with_stdio(0);cin.tie(0);
  cin>>n;
  for(int i=1,a,b;i<=n;i++){
    string s; cin>>s;
    if(s[0]>='A' && s[0]<='Z') a=s[0]-'A';
    else a=s[0]-'a'+26;
    if(s[1]>='A' && s[1]<='Z') b=s[1]-'A';
    else b=s[1]-'a'+26;
    g[a][b]++; g[b][a]++;
    du[a]++; du[b]++;
  }

  int start=53,cnt=0;
  for(int i=0; i<52; i++)if(du[i]&1){ //如果度为奇数
    start=min(start,i);
    cnt++;
  }
  if(!(cnt==0||cnt==2)) //如果奇点数非0非2,则无解
    return cout<<"No Solution\n",0;
  
  if(start==53)for(int i=0; i<52; i++)
    if(du[i]){start=i; break;} //找出环的起点
    
  dfs(start);
  
  if(path.size()-1!=n) //如果不连通,则无解
    return cout<<"No Solution\n",0;
  
  reverse(path.begin(),path.end());
  for(auto i:path){
    if(i>=0 && i<26) cout<<(char)(i+'A');
    else cout<<(char)(i-26+'a');
  }
}

 

posted @ 2026-05-26 16:45  董晓  阅读(35)  评论(0)    收藏  举报