无序字母对 洛谷 1341 欧拉通路/欧拉回路

题目描述

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

分析

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

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

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

ps:c++自带的栈会爆。

code

#include
#include
#include
#include
#include
#include
#include

using namespace std;

int edge[3002][3002];
int s[3002];
int n,m;

int gg[30000];

int work(int k)
{
    if ((k>='A')&&(k<='Z'))
        return k-'A'+1;
    else 
        return k-'a'+27;
}  


void prints(int k)
{
     if (k<=26) 
        printf("%c",k+'A'-1);
     else 
         printf("%c",k+'a'-27);
}

int flag=0;

bool dfs(int x,int num)
{
    gg[num+1]=x;
    if (num==m)
    {
        for (int i=1;i<=n+1;i++)
            prints(gg[i]);
        flag=1;
        return true;
    }
    for (int i=1;i<=52;i++)
    {
        if (edge[x][i])
        {
            edge[x][i]=0;
            edge[i][x]=0;
            dfs(i,num+1);
            edge[x][i]=1;
            edge[i][x]=1;
            if (flag)  return true;
        }
    }
    gg[num+1]=0;
    return false;
}

int main()
{
    scanf("%d",&n);
    getchar();
    char x,y;
    m=n;
    for(int i=1;i<=n;i++)
    {
        char ss[3];
        scanf("%s",ss);
        int a=work(ss[0]),b=work(ss[1]);
        edge[a][b]=edge[b][a]=1;
        s[b]++,s[a]++;
    }
    int num=0;
    int small1=1000;
    int small2=1000;

    for (int i=1;i<=52;i++)
        if (s[i]&1) 
            num++,small1=min(small1,i);
        else
            if (s[i]) small2=min(small2,i);
    if ((num!=0)&&(num!=2))
        printf("No Solution");
    int small;
    if (num==0) 
        small=small2;
     else 
        small=small1;
    dfs(small,0);
 }

你可能感兴趣的:(c++,数学)