sgu 101 Domino (欧拉路)

题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=101

思路: 最裸的欧拉路的题目 把骨牌的每一面当成点 每一张骨牌的两面都建一条无向边 求出此图的一条欧拉路即可。

在此总结一下欧拉路的知识:

无向图的欧拉路的存在判定: 为连通图 度数为奇数的点的个数为0 or 2

欧拉路的输出:

1.度数为奇数的点的个数为0(此图存在欧拉回路)  任选一点 用dfs入栈记录 最后再倒着输出即可

2.度数为奇数的点的个数为2(非欧拉图)         选出度数为奇数的点 然后再进行dfs


代码中并查集的判联通部分可以用dfs代替


code:

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;

const int maxn=10500;
const int maxe=10500;

struct edge
{
    int to,next,flag;
} G[maxe];

int head[maxn],si,du[maxn],way[maxe];
int cnt,nn;
bool vis[10];

void add_edge(int s,int t)
{
    G[si].flag=true;
    G[si].to=t;
    G[si].next=head[s];
    head[s]=si++;
    G[si].flag=true;
    G[si].to=s;
    G[si].next=head[t];
    head[t]=si++;
}

int par[maxn],num[maxn];
void init(int n_)
{
    for(int i=0;i<=n_;i++){
        par[i]=i;
        num[i]=1;
    }
}
int Find(int x)
{
    if(x==par[x]) return x;
    return par[x]=Find(par[x]);
}
void unite(int x,int y)
{
    x=Find(x);
    y=Find(y);
    if(num[x]<num[y]){
        par[x]=y;
        num[y]+=num[x];
    }
    else{
        par[y]=x;
        num[x]+=num[y];
    }
}
bool same(int x,int y)
{
    return Find(x)==Find(y);
}

void dfs(int vv,int tt)
{
    for(int i=head[vv];i!=-1;i=G[i].next){
        if(!G[i].flag) continue;
        G[i].flag=G[i^1].flag=false;
        dfs(G[i].to,i);
    }
    if(tt!=-1) way[cnt++]=tt;
}

void output(int kk)
{
    cnt=0;
    if(kk==0){
        for(int i=0;i<=6;i++){
            if(!vis[i]) continue;
            dfs(i,-1);
            break;
        }
    }
    else{
        for(int i=0;i<=6;i++){
            if(!vis[i]) continue;
            if(du[i]%2!=0){
                dfs(i,-1);
                break;
            }
        }
    }
    for(int i=cnt-1;i>=0;i--){
        if(way[i]%2) printf("%d -\n",way[i]/2+1);
        else         printf("%d +\n",way[i]/2+1);
    }
}

int main()
{
    int N,s,t,cnt1,cnt2,nn;
    bool mark;
    while(scanf("%d",&N)!=EOF){
        init(N);
        nn=0;
        memset(vis,0,sizeof(vis));
        memset(du,0,sizeof(du));
        memset(head,-1,sizeof(head));
        si=0;
        for(int kk=0;kk<N;kk++){
            scanf("%d%d",&s,&t);
            add_edge(s,t);
            du[s]++;
            du[t]++;
            if(!same(s,t))  unite(s,t);
            vis[s]=vis[t]=true;
        }
        for(int i=0;i<=6;i++) if(vis[i]) nn++;
        mark=0;
        for(int i=0;i<=6;i++){
            if(!vis[i]) continue;
            if(num[Find(i)]!=nn){
                printf("No solution\n");
                mark=1;
            }
            break;
        }
        if(mark==1) continue;
        cnt1=cnt2=0;
        for(int i=0;i<=6;i++){
            if(!vis[i]) continue;
            if(du[i]%2==0) cnt1++;
            else cnt2++;
        }
        if(cnt2==0) output(0);
        else if(cnt2==2) output(1);
        else printf("No solution\n");
    }
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值