SGU 101. Domino 欧拉回路

题目大意

给定你n张骨牌,每张牌左右两端有一个数字,每张牌的左右两端数字可以颠倒,找出一种摆放骨牌的顺序,使得相邻骨牌的两端数字相同(最左边骨牌的最左端和最右边骨牌的最右端可以不管)。

解题思路

这是个很普通无向图欧拉回路,但是要注意判断这个图是否在一个连通分量里面!
输出No solution的条件有两个
1. 如果不满足欧拉回路的性质就输出
2. 如果不在一个连通分量
对应于第一个就是判断每个节点度,如果是0个或者两个就是欧拉回路
对于第二个来讲如果有节点没有访问过,就代表有不止一个连通分量
然后如果是有奇数度就选从奇数度中的任意一个出发,如果没有奇数度就随便选一个度不为0的 节点出发

AC代码

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 250;
int head[MAXN],IN[MAXN];
int start,path[MAXN],tot,edgeCnt;
bool vis[MAXN];
struct Edge{
    int v,id,nxt;
}E[MAXN<<1];
void initEdge()
{
    edgeCnt = 0;
    tot = 0;
    memset(head,-1,sizeof head);
    memset(IN,0,sizeof IN);
    memset(vis,false,sizeof vis);
}

void addEdge(int u,int v,int id)
{
    E[edgeCnt].v = v;
    E[edgeCnt].id = id;
    E[edgeCnt].nxt = head[u];
    head[u] = edgeCnt++;
}
bool check()
{
    int count = 0;
    for(int i = 0; i <= 6; i++)
        if(IN[i]&1)
        {
            count++;
            start = i;
        }
    if(count == 1||count > 2) return false;
    if(count == 2) return true;
    for(int i = 0; i <= 6; i++)
        if(IN[i] > 0)
        {
            start = i;
            break;
        }
    return true;
}
void Fleury(int u)
{
    for(int i=head[u];~i;i=E[i].nxt)
    {
        int v = E[i].v;
        int id = E[i].id;
        if(!vis[(int)abs(id)])
        {
        //printf("[%d,%d]\n",v,id);
            vis[(int)abs(id)] = true;
            Fleury(v);
            path[tot++] = id;
        }
    }
}
int main()
{
    int M;
    int u,v;
    while(~scanf("%d",&M))
    {
        initEdge();
        for(int i=1;i<=M;i++)
        {
            scanf("%d%d",&u,&v);
            addEdge(u,v,i);
            addEdge(v,u,-i);
            IN[u]++;
            IN[v]++;
        }
        if(!check())
        {
            printf("No solution\n");
            continue;
        }
        //printf("[%d]",start);
        Fleury(start);
        for(int i=1;i<=M;i++)
            if(!vis[i]){
                printf("No solution\n");
                goto jumpEnd;
            }
        for(int i=tot-1;i>=0;i--)
            if(path[i]>0) printf("%d +\n",path[i]);
            else printf("%d -\n",-path[i]);
jumpEnd:;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值