poj1041 无向图欧拉回路 按最小升序输出

John's trip

这道题很不错,由于图已经保证连通,首先用度数是否是偶数,判断图是否是欧拉图,然后,输出最小升序,就成了一大难题,百科上有代码,这题让我理解了深搜的又一强大功能,其实就是每次都从小往大的搜,先搜得一个最小序环,然后对环上的每一点进行搜索,其实对于欧拉图而言,每个点要么就只剩一个点,什么也搜不到了,要么还有一个环,只要把环上路径全都插入到对应位置上,用栈存路径,每次只有回溯到当前点,就是说当前点的后继都已经搜过了的时候,才把当前点入栈,这样一来倒着输出,就能得到一个欧拉回路,而且是最小升序。

 
  
void dfs( int u){
int i, v, e;
for (i = 1 ; i <= num[u]; i ++ ){
e
= adj[u][i];
if ( ! mark[e]){
v
= map[u][e];
mark[e]
= 1 ;
dfs(v);
stk[
++ top] = e;
}
}
}

就是这样一个代码,就能实现欧拉回路的输出,唯一一点特别的就是,stk[++top] = e,是在v点搜完了才执行的,想想就知道这有什么含义,这样才是真正的最小序欧拉回路。实现代码见下:

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#include < stdio.h >
#include
< stdlib.h >
#include
< string .h >

#define NN 46
#define MM 1998

int map[NN][MM]; // map[u][e] = v,表示点u通过边e连接到v
int adj[NN][MM]; // adj[u][i] = e,表示u的第i条临边是e
int num[NN]; // 记录每个点的临边条数
int mark[MM];
int stk[MM]; // 记录欧拉路径
int idx, S, top;

int Min( int x, int y){
return x < y ? x : y;
}

int cmp( const void * a, const void * b){
return * ( int * )a - * ( int * )b;
}

void dfs( int u){
int i, v, e;
for (i = 1 ; i <= num[u]; i ++ ){
e
= adj[u][i];
if ( ! mark[e]){
v
= map[u][e];
mark[e]
= 1 ;
dfs(v);
stk[
++ top] = e;
}
}
}
int main()
{
int x, y, z, i, maxN;
while (scanf( " %d%d " , & x, & y) != EOF){
if (x == 0 && y == 0 ) break ;
memset(num,
0 , sizeof (num));
scanf(
" %d " , & z);
S
= Min(x, y);
adj[x][
++ num[x]] = z;
adj[y][
++ num[y]] = z;
map[x][z]
= y;
map[y][z]
= x;
while (scanf( " %d%d " , & x, & y) != EOF){
if (x == 0 && y == 0 ) break ;
scanf(
" %d " , & z);
adj[x][
++ num[x]] = z;
adj[y][
++ num[y]] = z;
map[x][z]
= y;
map[y][z]
= x;
}
for (i = 1 ;; i ++ ){
if (num[i] == 0 ) break ;
if (num[i] & 1 ) break ;
}
if (num[i] != 0 ){
puts(
" Round trip does not exist. " );
continue ;
}
maxN
= i - 1 ;
for (i = 1 ; i <= maxN; i ++ ){ // 对点i的临边排序
qsort(adj[i] + 1 , num[i], sizeof ( int ), cmp);
}
memset(mark,
0 , sizeof (mark));
top
= 0 ;
dfs(S);
for (i = top; i > 1 ; i -- ){
printf(
" %d " , stk[i]);
}
printf(
" %d\n " , stk[i]);
}
return 0 ;
}

 

转载于:https://www.cnblogs.com/ylfdrib/archive/2010/08/24/1807602.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值