P1341 无序字母对

按照题意建图,然后要求欧拉路径,对一个欧拉路径的判定
欧拉回路属于欧拉路径,而欧拉路径要求远比欧拉回路要求低。

无向图 当且仅当图中有两点度数为奇数,这两点为起点和终点,其他点度数皆为偶数且联通。
有向图 当且仅当其中一个顶点的入度少于出度1(起点),而另一点出度少于入度1(终点),其余节点出度=入度。图联通时。

至于为什么要倒着存,可以这样解释
input:
5
xx
xa
aa
ab
bx
output 50pts:
aabxax
output 100pts:
aabxxa

可以发现,50pts代码会贪心地挑较小结点访问,当访问到倒数第三个字母x时,会毫不犹豫地前往a,而不管这样做是否能遍历完,因此走到a无路可走了,又回到x遍历另外一个x,从而得到一个错误的答案
而100pts代码的好处在于,它是在遍历结束后将该结点逆序存入答案中,这就保证了无路可走的节点a一定是该序列的结尾(因为如果该结点还能继续访问,它就一定在那些能继续访问的点的前面),然后回到倒数第三个字母x寻找下一个x访问。此处不用担心x是否也是一个结尾(那样就无解了),因为通过递归前的判断,这张图中一定存在欧拉路,也就是只有一个终点

const int N=10007;
int m;
std::string s;
int g[N][N];
int ot[N];
char a[N];
int ans;
inline void print(){
	drp(i,ans,1){
		cout<<a[i];
	}
	cout<<'\n';
}

inline void dfs(int x){
	rep(j,1,150){
		if(g[x][j]){
			--g[x][j];
			--g[j][x];
			dfs(j);
		}
	}
	a[++ans]=x;
}
int main(){
	std::ios::sync_with_stdio(false);
	cin>>m;
	rep(i,1,m){
		cin>>s;
		++g[s[0]][s[1]];
		++g[s[1]][s[0]];
		++ot[s[0]];
		++ot[s[1]];
	}
	int cnt(0),a(0);
	rep(i,1,150){
		if(ot[i]&1){
			++cnt;
			if(!a) a=i;
		}
	}
	if(!a) {
		rep(i,1,150){
			if(ot[i]) {
				a=i;
				break;
			}
		}
	}
	
	if(cnt&&cnt!=2){
		puts("No Solution");
		return 0;
	}
	dfs(a);
	if(ans!=m+1){
		puts("No Solution");
		return 0;
	}
	print();
	return 0;
}

本文来自博客园,作者:{2519},转载请注明原文链接:https://www.cnblogs.com/QQ2519/p/15573657.html

原文地址:https://www.cnblogs.com/QQ2519/p/15573657.html