P1341 无序字母对
根据题意,只有在每两个相邻的字母都构成一个要求的无序字母对时,才能满足要求,
我们不妨将每个字母看成一个节点,每个无序字母对看成一个无向边,
我们要从一个点出发,不重复地走完所有的边,
所走的路径上的点构成的字符串即为一个合法的解
这就转化成了求一条字典序最小的欧拉路径
字典序就用堆搞一下就行了
如何判断是否存在欧拉路径:
对于无向图,
欧拉图(存在欧拉回路):该图是连通的且每个点的度数都是偶数
半欧拉图(存在欧拉路径):该图连通且仅有两个点的读数是奇数,这两个点即为欧拉路径的起始点
对于有向图:
欧拉图:该图的基图是连通的且所有点的入度等于出度
半欧拉图:该图的基图是连通的且只有一个点的入度比出度少1(起点),只有一个点的入度比出度多1(终点)
代码:
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; #define N 55 #define M 6010 int n=52,m,du[M],path[M],num; int Head[N],to[M],next[M],cnt=1; bool u[N],vis[N],cut[M]; inline int pos(char c){ if('A'<=c&&c<='Z') return c-'A'+1; else return c-'a'+27; } inline char map(int x){ if(1<=x&&x<=26) return x+'A'-1; else return x+'a'-27; } struct cmp{ bool operator()(int a,int b){ return to[a]>to[b]; } }; inline void add(int x,int y){ to[++cnt]=y; next[cnt]=Head[x]; Head[x]=cnt; } void dfs(int t){ priority_queue< int , vector<int> , cmp > que; for(int i=Head[t];i;i=next[i]) que.push(i); while(!que.empty()){ int i=que.top(); que.pop(); if(!cut[i]){ vis[to[i]]=1; cut[i]=cut[i^1]=1; dfs(to[i]); } } path[++num]=t; } int main() { char s[3]; scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%s",s); int x=pos(s[0]),y=pos(s[1]); u[x]=u[y]=1; add(x,y); add(y,x); du[x]++; du[y]++; } bool f=0; int st=0,tot=0; for(int i=1;i<=n;i++){ if(du[i]%2==1){ tot++; if(!f){st=i;f=1;} if(tot>2){ puts("No Solution"); return 0; } } } if(tot==0) for(int i=1;i<=n;i++) if(u[i]) { st=i; break; } vis[st]=1; dfs(st); for(int i=1;i<=n;i++) if(u[i]&&!vis[i]){ puts("No Solution"); return 0; } num++; while(--num) putchar(map(path[num])); return 0; }