Uva10129(DFS搜索+联通集)

题目地址:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=838&problem=1070&mosmsg=Submission+received+with+ID+21459508

题目分析:

n个单词形成序列,能够使每一个单词的第一个字母和上一个单词的最后一个字母相同,即是否形成欧拉通路,所以先以每个单词的首、尾形成点,连成有向边构图。但需要注意的是:只能存在一个欧拉通路(即一个联通集)!这可以通过递归完一次dfs搜索后,再一次扫描所有单词,判断是否还存在没有访问到的边。

代码如下:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 100;

int T, n, G[maxn][maxn], c[maxn], in[maxn], out[maxn];
int vis[maxn];		//判断边的关系 
char s[1010];

void read_word(){
	for(int i = 0;i < n;i++){
		scanf("%s",s);
		int len = strlen(s);
		int r = s[0] - 'a';		//首字母
		int t = s[len - 1] - 'a';		//尾字母 
		G[r][t] = 1;		//记录边的关系 
		out[r]++;in[t]++;
		vis[r] = vis[t] = 0;		//设置为未访问状态 
	}
}


void dfs(int u){
	vis[u] = 1;		//设置为访问状态 
	for(int v = 0; v < 26;v++)
		if(!vis[v] && G[u][v]) dfs(v);        //递归寻找所有u的子孙
}

int main(void){
	//freopen("data.out","w",stdout);
	scanf("%d",&T);
	while(T--){
		memset(vis,-1,sizeof(vis)); 
		memset(G,0,sizeof(G));
		memset(in,0,sizeof(in));
		memset(out,0,sizeof(out));
		scanf("%d",&n);
		
		read_word();
		
		int p = 0, begin = 0, tail = 0, cnt = 0;
		
		int flag = 0;
		for(int i = 0;i < 26;i++){
			if(out[i] == in[i]){	//中间节点,则跳过下面的步骤 
				continue;
			}
			if(out[i] == in[i] + 1){	//是起始点 
				begin++;p = i;
			} else if(in[i] == out[i] + 1)		//终止点 
				tail++;
			else
				cnt++;		//入度不等于出度,并且不为起始点或者终止点 
		}
		
		if(cnt > 0){		//如果个别节点 
			cout<<"The door cannot be opened.\n";
			continue;
		}	
		
		if(begin == 1 && tail == 1 || begin == 0 && tail == 0)	//有一个奇度起点与终点,或者全部为偶数度顶点 
			flag = 1;
		else 
			flag = 0;
		
		
		dfs(p);        //dfs返回后扫描完了一个联通集
		//扫描所有字母,判断只有一个联通集
		for(int i = 0;i < 26;i++){
			if(!vis[i]) flag = 0;		//如果还有未访问的联通集 
		} 	
		
		if(flag) cout<<"Ordering is possible.\n";
		else cout<<"The door cannot be opened.\n";
	}
	return 0;
}
posted @ 2018-06-11 21:02  Western_Trail  阅读(110)  评论(0编辑  收藏  举报