题目大意
给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。若有多解,输出字典序最小的那一个。
题解
首先由n+1可以想到什么?一条条边首尾相接,端点数便是边数+1。所以这道题就是一个欧拉路径问题。
欧拉路径的判定:度数为奇数的点为0个或2个。
欧拉路径的遍历:从一个度数为奇数的点(有度数为奇数的点的情况)或任意一点(无度数为奇数的点的情况)开始Dfs,存在没有被访问的边就沿边Dfs下去(节点可以重复走),最后将节点按Dfs逆后序输出即为答案。
如何满足字典序最小:我们按照逆后序输出,我们应当让每个节点的出边节点编号递增,这样可以使得先Dfs到编号低的节点,过后再从编号高的节点回来,使得编号高的节点先入栈,逆后序输出时编号高的节点会越靠后。
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <stack> using namespace std; #define Char_Inten(c) (c >= 'a' ? c - 'a' + 27 : c - 'A' + 1) #define Int_Charten(x) (x <= 26 ? x - 1 + 'A' : x - 27 + 'a') const int MAX_NODE = 100, MAX_EDGE = MAX_NODE * MAX_NODE, INF = 0x3f3f3f3f; bool IntenCharVis[MAX_NODE]; int IntenChar_NodeId[MAX_NODE], NodeId_IntenChar[MAX_NODE]; int TotNode; struct ElurianGraph { private: struct Node; struct Edge; struct Node { Edge *Head; int Degree; //bool Vis; }_nodes[MAX_NODE], *Start, *Target; int _vCount; struct Edge { Edge *Next, *Rev; Node *From, *To; bool Vis; }_edges[MAX_EDGE]; int _eCount; stack<Edge*> EdgeSt; Edge *AddEdge(Node *from, Node *to) { Edge *e = _edges + ++_eCount; e->From = from; e->To = to; Node *prevTo = NULL; Edge **InsNext = &from->Head; while (true) { if (!*InsNext || (prevTo <= e->To && e->To <= (*InsNext)->To)) { e->Next = *InsNext; *InsNext = e; break; } else { prevTo = (*InsNext)->To; InsNext = &(*InsNext)->Next; } } return e; } void Dfs(Node *cur) { _printf("Visiting %d ", cur - _nodes); //if (cur->Vis) // return; //cur->Vis = true; for (Edge *e = cur->Head; e; e = e->Next) { if (!e->Vis) { e->Vis = e->Rev->Vis = true; Dfs(e->To); EdgeSt.push(e); } } } public: void Init(int n) { _vCount = n; _eCount = 0; Start = Target = NULL; } void Build(int u, int v) { Edge *e1 = AddEdge(_nodes + u, _nodes + v); Edge *e2 = AddEdge(_nodes + v, _nodes + u); e1->Rev = e2; e2->Rev = e1; _nodes[u].Degree++; _nodes[v].Degree++; } bool IsConnect() { for (int i = 1; i <= _vCount; i++) { if (_nodes[i].Degree & 1) { if (Target) return false; else if (Start) { Target = _nodes + i; if (Start > Target) swap(Start, Target); } else Start = _nodes + i; } } bool ans = (Start && Target) || !(Start || Target); if (!Start) Target = Start = _nodes + 1; return ans; } int *GetOrder() { int *ans = new int[MAX_EDGE]; Dfs(Start); int i = 0; ans[++i] = EdgeSt.top()->From - _nodes; while (!EdgeSt.empty()) { ans[++i] = EdgeSt.top()->To - _nodes; EdgeSt.pop(); } ans[++i] = 0; return ans; } }g; void GetChar_NodeId() { TotNode = 0; for (int intenChar = 1; intenChar <= 52; intenChar++) if (IntenCharVis[intenChar]) { IntenChar_NodeId[intenChar] = ++TotNode; NodeId_IntenChar[TotNode] = intenChar; } } int main() { int n; scanf("%d", &n); static char ss[MAX_EDGE][10]; for (int i = 1; i <= n; i++) { scanf("%s", ss[i] + 1); IntenCharVis[Char_Inten(ss[i][1])] = IntenCharVis[Char_Inten(ss[i][2])] = true; } GetChar_NodeId(); g.Init(TotNode); for (int i = 1; i <= n; i++) g.Build(IntenChar_NodeId[Char_Inten(ss[i][1])], IntenChar_NodeId[Char_Inten(ss[i][2])]); if (!g.IsConnect()) { printf("No Solution "); return 0; } int *ans = g.GetOrder(); for (int i = 1; ans[i]; i++) printf("%c", Int_Charten(NodeId_IntenChar[ans[i]])); printf(" "); return 0; }