ZOJ1919 POJ2337 Catenyms,记录路径的欧拉图问题,同时路径是要按字典序输出

很恶心的一条题,欧拉回路和欧拉通路问题,不过要记录路径。先用原始的方法判断能不能够构成欧拉通路或者欧拉回路。然后用深度检索的方法来搜索可行解。每次输入都在当前节点的所有路径中按字典序排序,这样就可以保证输出是词典序了。


/*******************************************************************************
 # Author : Neo Fung
 # Email : [email protected]
 # Last modified: 2011-10-21 19:38
 # Filename: ZOJ1919 POJ2337 Catenyms.cpp
 # Description : 
 ******************************************************************************/
// #include "stdafx.h"
// #define DEBUG

#include <fstream>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>
#include <memory.h>
#include <math.h>
#include <algorithm>

using namespace std;

struct node
{
	int to,id;		//id代表这个节点在edge中的位置
	bool used;		//用于记录这个节点是否在深度优先搜索中用过
	string str;
	node *next;
}*adj[26],edge[2000],nTemp;

int cou,n,start;
int pre[26],ancient[2000],indegree[26],outdegree[26];	//pre用于并查集检索所有的路径是否连通,ancient用于记录每个单词出现顺序,indegree用于记录入度,outdegree用于记录出度

void init()
{
	memset(adj,'\0',sizeof(adj));
	memset(indegree,0,sizeof(indegree));
	memset(outdegree,0,sizeof(outdegree));
	for(int i=0;i<26;++i)
		pre[i]=-1;
	for(int i=0;i<n;++i)
		ancient[i]=-1;
	cou=0;
}
int find(const int &x)
{
	if(pre[x]==-1) pre[x]=x;
	return x==pre[x]?x:find(pre[x]);
}

bool check()
{
	int x=0;
	while(pre[x]==-1)
		++x;
	start = x;		//start用于记录起点,如果是欧拉回路的话,所有起点都可以,所以直接记录第一个了
	int tep = pre[x];
	for(;x<26;++x)
	{
		if(pre[x]!=-1)
			if(tep!=find(x))
				return false;	//不在同一棵树上,不行
	}

	int sum=0;
	int temp[26];
	memset(temp,0,sizeof(temp));
	for(x=0;x<26;++x)
		if(outdegree[x]!=indegree[x])
			temp[sum++]=x;

	if(sum==0)
		return true;	//欧拉回路

	if(sum ==2)		//欧拉通路
		if(outdegree[temp[0]]-indegree[temp[0]]==1 && indegree[temp[1]]-outdegree[temp[1]]==1)
		{
			start = temp[1];	//起点的入度比出度大1
			return true;
		}
		else if(outdegree[temp[1]]-indegree[temp[1]]==1 && indegree[temp[0]]-outdegree[temp[0]]==1)
		{
			start = temp[0];
			return true;
		}

	return false;
}

bool dfs(const int &s,const int &num)	//深度优先搜索,s是当前节点,num是当前深度
{
	int to,id;
	bool used;
	if(num==n)		//找到,返回
		return true;
	node *head=adj[s];

	while(head)
	{
		if(head->used)
		{
			head=head->next;
			continue;
		}
		to=head->to;
		id=head->id;
		ancient[num]=id;		//记录这条边
		head->used=true;	
		if(dfs(to,num+1))
			return true;
		head->used=false;
		head=head->next;
	}
	return false;
}

void input()
{
	cin>>edge[cou].str;
	string &str= edge[cou].str;
	int to = *str.rbegin()-'a';
	int from = *str.begin()-'a';
	edge[cou].to= to;
	edge[cou].id=cou;
	edge[cou].used=false;

	++indegree[from];
	++outdegree[to];

	int a=find(from);
	int b=find(to);
	pre[a]=pre[b]=pre[from]=pre[to]=min(a,b);		//并查集


	//以下三个判断,用于给每个节点按照词典序排序
	node *head=adj[from];
	if(!head || head&&head->str > str)		//string可以直接用<,>判断,返回结果是词典序结果。判断第一个节点是否存在,或者第一个节点存在且比本输入大
	{
		edge[cou].next=head;
		adj[from] = &edge[cou++];
	}
	else if(head && !head->next && head->str <str)		//第一个节点存在,第二个节点不存在,且第一个节点比本输入小
	{
		edge[cou].next = head->next;
		adj[from]->next = &edge[cou++];
	}
	else
	{
		while(head->next && head->next->str < str)		//找到一个位置,使得此位置的节点比本输入小,节点的下一个节点要么不存在,要么比本输入大
			head=head->next;
		edge[cou].next = head->next;
		head->next = &edge[cou++];
	}
}

int main(void)
{
#ifdef DEBUG  
	freopen("data.txt","r",stdin);  
#endif  
	int ncases;
	scanf("%d",&ncases);
	while(ncases--)
	{
		scanf("%d",&n);
		init();
		for(int i=0;i<n;++i)
			input();
		if(!check())
		{
			cout<<"***"<<endl;
			continue;
		}
		dfs(start,0);
		cout<<edge[ancient[0]].str;
		for(int i=1;i<n;++i)
		{
			cout<<'.'<<edge[ancient[i]].str;
		}
		cout<<endl;
	}

	return 0;
}


你可能感兴趣的:(ZOJ1919 POJ2337 Catenyms,记录路径的欧拉图问题,同时路径是要按字典序输出)