【训练题】无序字母对 P1675

Description

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


Input

第一行输入一个正整数n.以下n行每行两个字母,表示这两个字母需要相邻。


Output

输出满足要求的字符串。如果没有满足要求的字符串,请输出“No Solution”。如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案。


Hint

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


Solution

这道题需要计算一条欧拉路径,无序所以是无向图,由于数据规模较大用邻接矩阵来存会爆RE所以这个无向图只能用用vector来存,存的是char字符和每条边的id。字典序需要最小所以输入所有路径后需要将g从小到大进行排序。然后vector一个ep序列记录欧拉路径树的后序遍历结果,这里有一个需要注意的地方详见注意事项。


判断无解就需要记录每个结点的度,如果不等于0和2(即不是欧拉回路或者欧拉路),那么就直接输出无解后retrun 0。如果满足条件,因为字典序要最小所以要找到第一个最小的奇点,并且将start更新成它。如果没有奇点那么在init中已经将start更新成字典序最小的结点作为路径的开端了。然后就是欧拉路径dfs。


注意事项:

1.因为vector是从0位置开始输入并且size()返回的是+1的大小所以循环的时候从0开始且结束循环不用取等。
2.输入的时候不要用getchar()因为getchar会把回车输进去所以用一个str数组存字符串然后使起点和终点等于str[0]和str[1]。
3.存的是无向图所以一条边id要一样。
4.排序的时候循环是从字符'A'到'z',不是从1到n。
5.输出的时候将后序遍历结果倒着输出,同样需要注意size()不取等,结束在0位置。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 100005
using namespace std;
struct edge{
    char v;
    int id;
};
char x,y,start;
int n,cnt;
char str[5];
int num[maxn];
bool vis[maxn];
vector<edge>g[maxn];
vector<char>ep;
bool cmp(edge x,edge y){
    return x.v<y.v;
}
void init(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",str);
        x=str[0];
        y=str[1];
        if(i==1)start=x;
        if(start>x)start=x;
        if(start>y)start=y;
        g[x].push_back((edge){y,i});
        g[y].push_back((edge){x,i});
        num[x]++;
        num[y]++;
    }
    for(int i='A';i<='z';i++)
    sort(g[i].begin(),g[i].end(),cmp);
}
void find_circle(char x){
    for(int k=0;k<g[x].size();k++){
        char j=g[x][k].v;
        int id=g[x][k].id;
        if(vis[id])continue;
        else vis[id]=true;
        find_circle(j);
    }
    ep.push_back(x);
}
int main(){
    init();
    for(char i='A';i<='z';i++){
        if(num[i]%2==1){
            cnt++;
        }
    }
    if(cnt!=0&&cnt!=2){
        printf("No Solution\n");
        return 0;
    }
    if(cnt==2){
        for(int i='A';i<='z';i++){
            if(num[i]&1){
                start=i;
                break;
            }
        }
    }
    find_circle(start);
    for(int p=ep.size()-1;p>=0;p--){
        printf("%c",ep[p]);
    }
    putchar('\n');
    return 0;
}

转载于:https://www.cnblogs.com/virtual-north-Illya/p/10044986.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值