USACO Training Section 3.3 Riding the Fences

英文原题 
中文题译


经典的求欧拉路径:给定最多两个奇数度顶点的连通图(保证有欧拉回路),要求出欧拉路径使得每条边均访问到且只访问一次。附加条件:在所有可能欧拉回路中求按访问的节点序号的字典序最小的一个。

求欧拉回路最快的线性时间算法是这样的:从任意一个节点出发,每访问一个节点,就将其入栈,并删除所访问的边,如果到达一个没有边的顶点,则将栈顶元素出栈并输出之。

要在常数时间内删除边,邻接表中就不能存邻接节点,而需存对边的引用(可以是指针,或者是索引),这里用的是指针。从而在一个顶点将某边删除之后另一顶点可常数时间判断出来。

由欧拉回路算法求欧拉路径,只需从两个奇数度顶点之一出发即可,注意判断条件的变更。

本题的第二个限制,要求输出字典序最小的,这样在建立邻接表时顶点要排序,同时,删除边时不能简单的从最后挪一个边到相应位置来。一个最简单的方法就是每次按顺序访问邻接表找第一个未被删除的边。不过这样增加复杂度,更简单合理的方式是挪动邻接表的初始位置。(一般情况下,我们用adj[],n_adj表示邻接表,而这里用p_adj_head,p_adj_tail更为合理。)

可以考虑一下,如果要求按边出现顺序的字典序输出,该如何。


/*
ID: blackco3
TASK: fence
LANG: C++
*/
#include <iostream>
#include <algorithm>
#include <memory.h>
using namespace std;
const int _n_node_(500), _max_edge_(1024) ;
struct t_edge {
	int v1, v2 ;
	int used ;
} edge_pool[_max_edge_], *p_edge_pool[_max_edge_<<1];
bool edge_comp( t_edge const &pe1, t_edge const &pe2 ){
	return pe1.v1==pe2.v1 ? pe1.v2<pe2.v2 : pe1.v1<pe2.v1 ;
}
struct t_node {
	int n_adj ;
	t_edge **adj ;
} nodes[_n_node_] ;
int n_edge ;

int tour_stk[_max_edge_+2], top;
int tour( int v ){
	while(true){
		t_edge **ppe_head=nodes[v].adj, **ppe_tail=ppe_head+nodes[v].n_adj ; 
		while( ppe_head != ppe_tail && (*ppe_head)->used )
			ppe_head++ ;
		node[v].adj=ppe_head, node[v].n_adj=ppe_tail-ppe_head ;
		if( ppe_tail==ppe_head )
			break ;
		tour_stk[top++]=v ;
		(*ppe_head)->used=1; 
		v=(*ppe_head)->v1==v? ((*ppe_head)->v2):((*ppe_head)->v1);
	}
	return v ;
}

int main() {
	freopen("fence.in", "r", stdin);
	freopen("fence.out", "w", stdout);
	int n_edge ;
	cin >> n_edge;
	memset( nodes, 0, sizeof(nodes));
	for( t_edge *p_edge=edge_pool; p_edge!=edge_pool+n_edge; p_edge++ ){
		int v1, v2, tmp ;
		cin >> v1 >> v2 , tmp=--v1, --v2 ;
		if( v1>v2 )
			v1=v2 , v2=tmp ;
		p_edge->v1=v1, p_edge->v2=v2, p_edge->used = 0 ;
		nodes[v1].n_adj++, nodes[v2].n_adj++ ;
	}
	
	t_edge **pp_edge =p_edge_pool;
	int start_node=-1 , end_node=-1 ;
	for( int i=0; i<_n_node_; i++ ){
		nodes[i].adj = pp_edge , pp_edge += nodes[i].n_adj;
		if( nodes[i].n_adj&1 ) {
			if( start_node==-1 )
				start_node = i ;
			else
				end_node = i ;
		}
		nodes[i].n_adj = 0 ;
	}
	start_node = start_node==-1 ? 0 : start_node ;
	sort( edge_pool, edge_pool+n_edge, edge_comp) ;
	
	for( t_edge *p_edge=edge_pool; p_edge!=edge_pool+n_edge; p_edge++ ){
		int v1=p_edge->v1, v2=p_edge->v2 ;
		nodes[v1].adj[ nodes[v1].n_adj++ ] = p_edge ;
		nodes[v2].adj[ nodes[v2].n_adj++ ] = p_edge ;
	}

	int trace[_max_edge_+2], trace_size=0, v=start_node;
	top = 0 ;
	do {
		tour(v) ;
		if( !top )
			break ;
		v = tour_stk[--top];
		trace[trace_size++] = v ;
	} while ( true ) ;
	for( int i=trace_size-1; i>=0; i-- )
		cout << trace[i]+1 << endl ;
	if( end_node!=-1 )
		cout << end_node+1 << endl ;
	else
		cout << start_node+1 << endl ;
	return 0;
}

你可能感兴趣的:(C++,c,算法,C#,asp)