欧拉路径, 欧拉回路 USACO Riding the Fences

概念

欧拉回路:从图的某一个顶点出发,图中每条边走且仅走一次,最后回到出发点。如果这样的回路存在,则称之为欧拉回路。
欧拉路径:从图的某一个顶点出发,图中每条边走且仅走一次,最后到达某一个点。如果这样的路径存在,则称之为欧拉路径。

无向图, 欧拉回路存在条件:所有顶点的度数均为偶数。
无向图, 欧拉路径存在条件:至多有两个顶点的度数为奇数,其他顶点的度数均为偶数。
有向图, 欧拉回路存在条件:所有顶点的入度和出度相等。
有向图, 欧拉路径存在条件:至多有两个顶点的入度和出度绝对值差1(若有两个这样的顶点,则必须其中一个出度大于入度,另一个入度大于出度),
其他顶点的入度与出度相等。

在USACO上有一种算法,大体过程如下:
随机选择某一顶点,如果有度是奇数的顶点, 则从该顶点开始。然后随机选择一条与之相连的边,删除。递归访问与该边相连的节点,最后将该边存入路径,倒序输出即是一条欧拉路径或者欧拉回路。


解法

input 和 output 格式如下. 提供的算法主要针对无向图. 

如果想适用于有向图, 则需要进行简单修改,有向图起始点(outdegree == indegree+1 或者 outdegree = indegree).

INPUT FORMAT

Line 1:The number of fences, F (1 <= F <= 1024)
Line 2..F+1:A pair of integers (1 <= i, j <= 500) that tell which pair of intersections this fence connects.

SAMPLE INPUT (file fence.in)

9
1 2
2 3
3 4
4 2
4 5
2 5
5 6
5 7
4 6

OUTPUT FORMAT

The output consists of F+1 lines, each containing a single integer. Print the number of the starting intersection on the first line, the next intersection's number on the next line, and so on, until the final intersection on the last line. There might be many possible answers to any given input set, but only one is ordered correctly.

SAMPLE OUTPUT (file fence.out)

1
2
3
4
2
5
4
6
5
7

/*
LANG: C
TASK: fence
*/
#include<stdio.h>
#define maxn 501
#define Max(a, b) (a > b ? a : b)
#define Min(a, b) (a < b ? a : b)
int num[maxn], map[maxn][maxn], min, max, path[maxn], index = 0;
void circuit(int x)
{
    int i;
    if (num[x])
    {
        do
        {
            for (i = min; i <= max; i++)
            {
                if (map[x][i])//找最小的邻接点
                {
                    break;
                }
            }
            map[x][i]--, map[i][x]--, num[x]--, num[i]--;//删除该边 
            circuit(i);//搜索x的邻接点 
        }while (num[x]);
        path[index++] = x;//搜索点x的所有邻接点后才保存路劲x
    }
    else
    {
        path[index++] = x;
    }
}
void deal()
{
    int i;
    for (i = min; i <= max; i++)//如果有度为奇数的点,从奇数点搜索 
    {
        if (num[i] % 2 == 1)
        {
            circuit(i);
            return;
        }
    }
    circuit(min);//否则,任意一点都可以,但题意要求欧拉回路尽可能从小到大的顺序输出 
}
void print()
{
    int i;
    for (i = index - 1; i >= 0; i--) 
    {
        printf("%d\n", path[i]);
    }
}
void read()
{
    int i, n, u, v;
    scanf("%d", &n);
    for (i = 0, min = 500, max = 1 ; i < n; i++)
    {
        scanf("%d%d", &u, &v);
        map[u][v]++, map[v][u]++;
        num[u]++, num[v]++;
        if (max < Max(u, v))
        {
            max = Max(u, v);
        }
        if (min > Min(u, v))
        {
            min = Min(u, v);
        }
    }
}        
int main()
{
    freopen("fence.in", "r", stdin), freopen("fence.out", "w", stdout);
    read();
    deal();
    print();
    fclose(stdin), fclose(stdout);
    //system("pause");
    return 0;
}


转载自:http://www.cppblog.com/Ylemzy/articles/100050.html

http://www.cnblogs.com/aaronzlq/archive/2013/03/07/2948777.html


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值