poj 1386 | hdoj 1116 play on words

41 篇文章 0 订阅
32 篇文章 0 订阅

类型:欧拉回路

题目:http://poj.org/problem?id=1386

来源:Central Europe 1999

思路:首先考虑的是将单词看做点,可以连接的单词之间连一条边,这样就是求一条路径包含所有的点,该问题为复杂的哈密尔顿问题。

然后考虑转化模型,将单词看做边,每个单词的首尾字符看做点,那么每个单词就是一条由首字符点连向尾字符点的边,即转化为就一条路径连接所有的边

,即欧拉路径[回路]问题。当只有一个点的入度等于初度 + 1,一个点的初度等于入度 + 1,其他点的入度 = 初度,或者所有点入度 = 初度时,结果为真。

!!!需要用并查集判断图的连通性。

// poj 1386 play on words
// wa wa 125MS 264K
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
using namespace std;

#define FOR(i,a,b) for(i = (a); i < (b); ++i)
#define FORE(i,a,b) for(i = (a); i <= (b); ++i)
#define FORD(i,a,b) for(i = (a); i > (b); --i)
#define FORDE(i,a,b) for(i = (a); i >= (b); --i)
#define max(a,b) ((a) > (b)) ? (a) : (b)
#define min(a,b) ((a) < (b)) ? (a) : (b)
#define CLR(a,b) memset(a,b,sizeof(a))

const int MAXN = 1010;

int n, t;
int ru[30], chu[30], p[30];
char ch[MAXN];

void makeSet() {
	for(int i = 0; i <= 29; ++i)
		p[i] = i;
}

int findSet(int u) {
	return (u != p[u]) ? (p[u] = findSet(p[u])) : p[u];
}

void link(int x, int y) {
    p[x] = y;
}

bool solve() {
    int i, j, tmp, x = 0, y = 0;
    bool sign = false;

    FORE(i, 0, 25) {
        if(ru[i] == chu[i])
            continue;
        if(ru[i] == chu[i] - 1)
            ++x;
        if(ru[i] == chu[i] + 1)
            ++y;
        if(ru[i] - chu[i] > 1 || chu[i] - ru[i] > 1) {
            sign = true;
            break;
        }
    }
    if(sign)
        return false;
    FORE(i, 0, 25)
        if(ru[i] != 0 || chu[i] != 0) {
            tmp = findSet(i);
            break;
        }
    FORE(j, i + 1, 25)
        if(ru[j] != 0 || chu[j] != 0)
            if(tmp != findSet(j))
                return false;
    if((x == 1 && y == 1) || (x == 0 && y == 0))
        return true;
    return false;
}

int main() {
    int i;

    scanf("%d", &t);
    while(t--) {
        CLR(ru, 0), CLR(chu, 0);
        makeSet();
        scanf("%d", &n);
        FORE(i, 1, n) {
            scanf("%s", ch);
            int len = strlen(ch);
            if(findSet(ch[len - 1] - 'a') != findSet(ch[0] - 'a'))
                link(findSet(ch[len - 1] - 'a'), findSet(ch[0] - 'a'));
            ++ru[ch[len - 1] - 'a'];
            ++chu[ch[0] - 'a'];
        }
        if(solve())
            printf("Ordering is possible.\n");
        else
            printf("The door cannot be opened.\n");
    }
    return 0;
}
/*
2
2
ok
ko
4
ab
ba
ef
fe
*/



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值