无序字母对

1 篇文章 0 订阅

题目描述

给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。

输入输出格式

输入格式:
第一行输入一个正整数n。

以下n行每行两个字母,表示这两个字母需要相邻。

输出格式:
输出满足要求的字符串。

如果没有满足要求的字符串,请输出“No Solution”。

如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案

输入输出样例

输入样例#1:
4
aZ
tZ
Xt
aX
输出样例#1:
XaZtX

说明

【数据规模与约定】

不同的无序字母对个数有限,n的规模可以通过计算得到。

先简单说一下欧拉这个问题,欧拉通路即一笔画问题,就是在不走重复边的情况下走完全部的边,如果能回到起点即是欧拉回路

首先,看到题目,再看到样例,就会发现字母对是[b ]必须[/b ]连在一起的,然后就会想到图的遍历之类的。有点灵感的话想到欧拉图应该没什么问题。

然后建图就很清晰了。将字母作为图的顶点,如果两字母间存在字母对就在相应的字母所对应的顶点连上一条五向边。题目要求的是字典序最小的欧拉通路,怎么办呢?

欧拉通路存在的要求是只存在0个或2个度数为奇数的顶点,如果没有度数为奇数的顶点,那么这个图还存在欧拉回路。如果有同学不知道什么是欧拉通路或欧拉回路请自己去百度。欧拉通路的求法很简单,直接暴力DFS回溯就好,在这道题中先走字典序最小的顶点就OK了,令人惊讶的是这样做的效率竟然真的很不错。

如果有同学想用递推来写的话,可能会因为提前走进死路而WA,加点判断的话,就我个人来说得了80,望神犇指导。

此外,欧拉回路还有一个更优美的方法叫套圈法(好像是这名字吧),有兴趣的可以百度一下。

一点都不优美的代码:

#include <cstdio>
#include <stack>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 100;
int map[maxn][maxn], cnt[maxn], vis[maxn][maxn];
int n, maxm = 53;
stack <int> ans;

int zhuanhua1(char c)
{
    if (c >= 'A' && c <= 'Z')
        return (int)c - 'A';
    return (int)c - 'a' + 26;
}

char zhuanhuan2(int x)
{
    if (x >= 0 && x <= 25)
        return (char)x + 'A';
    return (char)(x - 26) + 'a';
}

void euler(int u)
{
    for (int v = 0; v < maxm; v++)
        if (map[u][v] && !vis[u][v])
        {
            vis[u][v] = vis[v][u] = 1;
            euler(v);
            ans.push(v);
        }
}

int main()
{
    scanf("%d%d", &n);
    for (int i = 1; i <= n; i++)
    {
        char a, b;
        cin >> a >> b;
        int x = zhuanhua1(a), y = zhuanhua1(b);
        map[x][y] = map[y][x] = 1;
        cnt[x]++;
        cnt[y]++;
    }
    int tot = 0, min1 = 1e8, min2 = 1e8;
    for (int i = 0; i < maxm; i++)
    {
        if (cnt[i]%2==1)
        {
            tot++;
            min1 = min(min1, i);
        }
        else if (cnt[i])
            min2 = min(min2, i);
    }
    if (tot != 0 && tot != 2)
        printf("No Solution\n");
    else
    {
        int u;
        if (tot == 0)
            u = min2;
        else
            u = min1;
        euler(u);
        ans.push(u);
        while (!ans.empty())
        {
            int temp = ans.top();
            ans.pop();
            char s = zhuanhuan2(temp);
            cout << s;
        }
        printf("\n");
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值