欧拉回路 无序字母队
欧拉路径
题目描述
给定 nnn 个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有 (n+1)(n+1)(n+1) 个字母的字符串使得每个字母对都在这个字符串中出现。
输入格式
第一行输入一个正整数 nnn。
第二行到第 (n+1)(n+1)(n+1) 行每行两个字母,表示这两个字母需要相邻。
输出格式
输出满足要求的字符串。
如果没有满足要求的字符串,请输出 No Solution
。
如果有多种方案,请输出字典序最小的方案(即满足前面的字母的 ASCII 编码尽可能小)。
输入输出样例
输入 #1
4 aZ tZ Xt aX
输出 #1
XaZtX
说明/提示
不同的无序字母对个数有限,nnn 的规模可以通过计算得到。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int n; 5 int vhash[1100][1100]; 6 int tot=0; 7 int vis[11000]; 8 int gin[11000]; 9 10 void readp(){ 11 cin>>n; 12 for(int i=1;i<=n;i++){ 13 string st; 14 cin>>st; 15 int x,y; 16 x=st[0];y=st[1]; 17 vis[st[0]]=1; 18 vis[st[1]]=1; 19 vhash[x][y]++;vhash[y][x]++; 20 gin[x]++; 21 gin[y]++; 22 } 23 } 24 25 int ans[11100],cnt=0; 26 27 void dfs(int pos){ 28 for(int i='A';i<='Z';i++) 29 if(vhash[i][pos]>0){ 30 vhash[i][pos]--;//删边大法好 31 vhash[pos][i]--; 32 dfs(i); 33 } 34 for(int i='a';i<='z';i++) 35 if(vhash[i][pos]>0){ 36 vhash[i][pos]--; 37 vhash[pos][i]--; 38 dfs(i); 39 } 40 ans[++cnt]=pos; 41 } 42 43 void work(){ 44 int tip=-1; 45 int qt=0; 46 for(int i='A';i<='Z';i++) 47 if(vis[i]==1){ 48 if(gin[i]%2!=0)qt++; 49 if(tip==-1)tip=i; 50 if(gin[tip]%2==0&&gin[i]%2!=0){ 51 tip=i; 52 } 53 }//两者效果一样,只不过是两个分开的解集 54 for(int i='a';i<='z';i++) 55 if(vis[i]==1){ 56 if(gin[i]%2!=0)qt++; 57 if(tip==-1)tip=i; 58 if(gin[tip]%2==0&&gin[i]%2!=0){ 59 tip=i; 60 } 61 } 62 63 dfs(tip); 64 //判断it is very important 65 if(qt&&qt!=2)cout<<"No Solution"<<endl; 66 else if(cnt<n+1)cout<<"No Solution"<<endl; 67 else { 68 for(int i=cnt;i>=1;i--) 69 cout<<char(ans[i]); 70 cout<<endl; 71 } 72 } 73 74 int main(){ 75 readp(); 76 work(); 77 return 0; 78 }
1 #include<bits/stdc++.h>//万能头 2 using namespace std; 3 const int maxn=10000+10; 4 int n,m,dis[maxn][maxn],s1=maxn,ans;//dis是用来存两点的连接 5 char ru[maxn],a[maxn];//ru存度数,a存路径 6 void out(){//写了个输出函数 7 for(int i=ans;i>=1;i--) 8 printf("%c",a[i]); 9 cout<<endl; 10 } 11 void find(int i){//开始找欧拉路,i表示找的当前这个点 12 for(int j=1;j<=150;j++)//最大的小写z是肯定没超过150的,所以枚举点循环到150就行了 13 if(dis[i][j]>0){//如果两点之间有连通 14 dis[i][j]--;//毁图大法好 15 dis[j][i]--; 16 find(j);//搜索下一个点 17 } 18 a[++ans]=i;//记录路径 19 return ; 20 } 21 int main(){ 22 cin>>m; 23 for(int i=1;i<=m;i++) 24 { 25 string s; 26 cin>>s;//这里我是采用string处理的,char也行不影响 27 dis[s[0]][s[1]]++;//记录路径,数组第一维表示当前的点,与第二维的点有,连接 28 dis[s[1]][s[0]]++; 29 ru[s[0]]++;//记录度数 30 ru[s[1]]++; 31 } 32 int cnt=0,h=0;//开始找点 33 for(int i=1;i<=150;i++)//在找度数为奇数的点 34 if(ru[i]&1){ 35 cnt++; 36 if(!h)h=i; 37 } 38 if(!h)//找不到奇点,就是另外找点 39 for(int i=0;i<150;i++) 40 if(ru[i]){h=i;break;} 41 if(cnt&&cnt!=2){ 42 cout<<"No Solution"; 43 return 0; 44 } 45 find(h); 46 if(ans<m+1){//这就是我之前所说的巧妙一点的方法,实际上只要搜完以后判断一下,点数是不是相等就行了,因为m组连边,必有m+1个点,前提是不重复 47 cout<<"No Solution"; 48 return 0; 49 } 50 out();//输出 51 return 0;//完结散花 52 }