poj2337(gcc)

poj2337 欧拉路问题  
通过并查集判定图是否连通;根据条件判定是否存在欧拉路,即或者所有顶点的入度和出度相等,或者有且仅有两个顶点,一个顶点的入度等于出度加一,另一个顶点的入度加一等于出度;通过深搜求出欧拉路径。这道题目将每个单词的首尾字母抽象成顶点,当两个顶点属于同一个单词时,则存在一条单词头部字母对应的顶点指向单词尾部字母对应的顶点的弧,存储采用了邻接表的方式,数组adj是头部数组,node对应的adjlist数组则存储对应邻接边。
#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#define maxn 1001
#define num 26
typedef struct node{
	int next, adj;
	char word[21];
}node;
node adjlist[maxn];
int adj[num];
int deg[num];
int vis[maxn];
int top, stack[maxn];
int tree[num];
int et[num];

int findRoot(int u){
	if(tree[u] == -1)	return u;
	int v = findRoot(tree[u]);
	tree[u] = v;
	return v;
}

int cmp(const void *x, const void *y){
	node *_x = (node *)x;
	node *_y = (node *)y;
	return strcmp(_y->word, _x->word);
}
void createGrapic(){
	int i, e;
	scanf("%d", &e);
	for(i = 0; i < e; ++i)
		scanf("%s", adjlist[i].word);
	memset(adj, -1, sizeof(adj));
	memset(deg, 0, sizeof(deg));
	memset(vis, 0, sizeof(vis));
	memset(tree, -1, sizeof(tree));
	memset(et, 0, sizeof(et));
	qsort(adjlist, e, sizeof(node), cmp);
	for(i = 0; i < e; ++i){
		int len = strlen(adjlist[i].word);
		int start = adjlist[i].word[0]-'a', end = adjlist[i].word[len-1]-'a';
		--deg[start];
		++deg[end];
		adjlist[i].next = adj[start];
		adj[start] = i;
		adjlist[i].adj = end;
		et[start] = 1; et[end] = 1;
		int p = findRoot(start);
		int q = findRoot(end);
		if(p != q)
			tree[p] = q;
	}
}

void euler(int u){
	int v;
	for(v = adj[u]; v != -1; v = adjlist[v].next){
		if(!vis[v]){
			vis[v] = 1;
			euler(adjlist[v].adj);
			stack[top++] = v;
		}
	}
}

int main(){
	int i, N, w;
	scanf("%d", &N);
	while(N--){
		w = 0;
		createGrapic();
		for(i = 0; i < num; ++i){
			if(et[i])	if(tree[i] == -1)	++w;
		}	
		if(w > 1){	printf("***\n");	continue;}
		top = 0;
		int pos = 0, neg = 0, oth = 0, k, flag = 0;
		for(i = 0; i < num; ++i)
			if(deg[i] == 1)	++pos; 
			else	if(deg[i] == -1)	{++neg; k = i;}
			else	if(deg[i] != 0)		++oth;
		if(neg==0 && pos==0 && oth==0){
			for(i = 0; i < num; ++i)
				if(adj[i] != -1){euler(i); flag = 1; break;}	
		}
		else	if(neg==1 && pos==1 && oth==0){euler(k); flag = 1;}
		else	printf("***\n");
		if(flag){
			while(--top)	printf("%s.", adjlist[stack[top]].word);
			printf("%s\n", adjlist[stack[top]].word);
		}			
	}
	return 0;
}

     
     
    
    
   
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值