uva 10129 Play on Words

本文介绍了一种使用欧拉图和半欧拉图理论解决UVA10129问题的方法,通过构建单词之间的图结构,并利用广度优先搜索和并查集等算法验证图的强连通性和欧拉路径的存在性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//
//  main.cpp
//  uva  10129 Play on Words
//
//  Created by XD on 15/7/19.
//  Copyright (c) 2015年 XD. All rights reserved.
//

//注意欧拉图的定义,此题中需要用到欧拉图和半欧拉图的定义
//解题思路 :每个单词可以看成是一条从首字母到最后的那个字母的一条边形成一个图,要是能够按照题目的要求将所有单词连接在一起,则要求图是欧拉图或是欧拉图,然后则可以根据定理来解决这个问题,判断弱连通性则可以使用并查集来计算,判断强连通性可以使用如下的规则
/*
 1.从某个节点s开始广度优先遍历,若不能遍历所有的点,则说明不是强连通图
 2.求原图的逆图
 3.从节点s开始广度遍历,若能够遍历所有的点,说明原图是强连通图,反之则不是。
 */


//

#include <iostream>
#include <string>
#include <queue>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include<vector>
#include <string.h>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <cstdio>
using namespacestd ;


int din[30] ;
int dout[30] ;
set<int > v ;
int g[30][30] ;
int flag[30] ;


//带秩和路劲压缩的并查集
int p[30] ;
int r[30] ;
void init()
{
    for (int i = 0; i < 30; i++) {
        p[i] = i;
        r[i] = 0 ;
    }
}
int find_set(int x)
{
    if (p[x] != x) {
        p[x] =find_set(p[x]) ;
    }
    returnp[x]  ;
}
void link(int x ,int  y)
{
    if (r[x] >r[y]) {
        p[y] = x ;
    }else{
        p[x] = y  ;
        if (r[x] ==r[y]) {
            r[y]+=1 ;
        }
    }
}


void UNION(int x ,int y )
{
    link(find_set(x) ,find_set(y)) ;
}

//广度优先遍历
bool bfs(int  x,int  n )
{
    queue<int > q ;
    q.push(x) ;
    
    flag[x]=1 ;
    int num =1 ;
    while (!q.empty()) {
        int first = q.front() ;q.pop() ;
        for (int i = 0  ;i < 26 ; i++) {
            if (g[first][i] == 0) {
                continue ;
            }
            int to = i;
            if (flag[to] == 0) {
                flag[to] = 1 ;
                q.push(to) ;
                num++ ;
            }
        }
    }
    if (num == n) {
        returntrue ;
    }
    returnfalse ;
}
//矩阵转置
void inverse()
{
    for (int i = 0; i < 30; i++) {
        for (int j = i; j < 30; j++) {
            int temp =g[i][j] ;
            g[i][j] =g[j][i] ;
            g[j][i] =temp ;
        }
    }
}

int main() {
    
    int casenum  ;
    int n ;
    char s[1010] ;
    int odd ;
    scanf("%d" ,&casenum) ;
    int temp = 0 ;
    while (casenum--) {
        //初始化
        memset(flag, 0,sizeof(flag)) ;
        memset(g, 0,sizeof(g)) ;
        v.clear()  ;
        memset(din, 0,sizeof(din))  ;
        memset(dout, 0,sizeof(dout)) ;
        scanf("%d" , &n)   ;
        init() ;
        
        
        int u,t ;
        for (int i= 0  ; i < n ; i++) {
            scanf(" %s" , s) ;
            u = s[0]-'a' ; t = s[strlen(s)-1]-'a' ;
            dout[u]++ ;din[t]++ ;
            temp = u ;
            if(find_set(u) !=find_set(t))
            {
                UNION(u, t) ;
            }
           g[u][t] =1  ;
            v.insert(u) ;v.insert(t ) ;
        }
        //统计奇数度点的个数
        odd= 0 ;
        int flag1 = 0;
        for(set<int >::iterator it = v.begin() ; it!=v.end() ; it++)
        {
            if (din[*it]!=dout[*it])
            {
                if((din[*it]+dout[*it]) % 2 == 1)
                {
                    odd++ ;
                    if (odd > 2 ||din[*it] - dout[*it] > 1 ||din[*it] - dout[*it] <-1 ) {
                        flag1=1 ;
                        break ;
                    }
                }
                else{
                    flag1 = 1;
                    break ;
                }
            }
        }
        
        if(flag1 == 1)
        {
            printf("The door cannot be opened.\n") ;
            continue ;
        }
        //是不是欧拉图
        if (odd == 0)  {
            if (!bfs(temp, (int )v.size())){
                printf("The door cannot be opened.\n") ;
                continue ;
            }
            inverse() ;
             memset(flag, 0,sizeof(flag)) ;
            if (!bfs(temp, (int )v.size())){
                printf("The door cannot be opened.\n") ;
                continue ;
            }
            printf("Ordering is possible.\n" ) ;
        }
        //半欧拉图
        elseif(odd == 2){
            temp = -1 ;
            flag1 = 0 ;
            for(set<int >::iterator it = v.begin() ; it!=v.end() ; it++)
            {
                if (temp ==  -1) {
                    temp =find_set(*it)  ;
                }
                else{
                    if(find_set(*it) != temp ){
                        flag1 = 1 ;
                        break  ;
                    }
                }
            }
            if (flag1 == 1) {
                printf("The door cannot be opened.\n") ;
                continue ;
            }
            printf("Ordering is possible.\n" ) ;
        }
        else{
            printf("The door cannot be opened.\n") ;
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值