D168 欧拉路径 P1341 无序字母对
D168 欧拉路径 P1341 无序字母对_哔哩哔哩_bilibili
给定 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'); } }
浙公网安备 33010602011771号