题目大意
给定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;
}