CF508D

题解

考虑把每一个串的前两位和后两位分别看成一个点(字符串哈希),从前向后连边,问题转化成求所建图的欧拉路径。
对于有向图的欧拉路径,常规操作请移步P7771 【模板】欧拉路径
对于本题而言,有一点易错的细节:

  • 有自环,重边,所以点数我开到 (256 imes 256),但边数还是 (2 imes 10^5)
  • 图可能不连通,所以加上一条判断,如果栈内元素是 (n+1) 个才有解。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define FCC fclose(stdin),fclose(stdout)
const int INF = 0x3f3f3f3f,base=256,N = 257*257;
inline ll read()
{
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
int n;
int head[N],ecnt=-1;
int ind[N],oud[N];
inline void init_edge(){memset(head,-1,sizeof(head)),ecnt=-1;}
struct edge
{
	int nxt,to;
}a[200005];
bool vis[N];
inline void add_edge(int x,int y)
{
	a[++ecnt]=(edge){head[x],y};
	head[x]=ecnt;
	ind[y]++,oud[x]++;
	vis[x]=1,vis[y]=1;
}

int S,T,stk[N],top;
char str[N][3];
void dfs(int u)
{
	for(int i=head[u];~i;i=head[u])
	{
		int v=a[i].to;
		head[u]=a[i].nxt;//链前的删边操作 
		dfs(v);
	}
	stk[++top]=u;
}
int main()
{
	init_edge();
	n=read();
	for(int i=1;i<=n;i++)	
	{
		char s[6];
		scanf("%s",s+1);
		int u=(s[1]-'0'+1)*base+s[2]-'0'+1;
		int v=(s[2]-'0'+1)*base+s[3]-'0'+1;
		add_edge(u,v);
		str[u][1]=s[1],str[u][2]=s[2];
		str[v][1]=s[2],str[v][2]=s[3];
		//cout<<str[u]<<'
';
		//printf("%d->%d
",u,v);
		S=u;
	}
	int cnt=0;
	for(int i=0;i<=256*256;i++)
	{
		if(!vis[i]) continue;
		if(oud[i]-ind[i]==1) S=i;
		if(oud[i]-ind[i]==-1) T=i;
		if(abs(oud[i]-ind[i])>1) return puts("NO"),0;
		cnt+=(oud[i]!=ind[i]);
	}
	if(cnt!=2&&cnt) return puts("NO"),0;
	
	dfs(S);
	//printf("S=%d,top=%d
",S,top);
	if(top+1!=n+2) return puts("NO"),0;
	bool fir=0;
	puts("YES");
	while(top) 
	{
		if(!fir) printf("%c",str[stk[top]][1]),fir=1;
		printf("%c",str[stk[top]][2]),top--;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/conprour/p/15532958.html