无序字母对

传送门

一道非常不错的欧拉回路(路径)题……

我们已经知道怎么求欧拉回路(路径)了,但是如果求字典序最小的呢?

求欧拉回路是一个深搜的过程……所以我们不如每次在向下一个点深搜的时候,每次让他先走那个字典序最小的节点,这样我们就能保证字典序最小了。不过实际上这个用邻接表实现会很麻烦。我的实现方法是,对于所有的边,我们先把它拆成两条有向边,对于拆出来的边赋予相同的id,之后我们把边按照起始点和终点排个序(注意邻接表的存储方法,终点要倒着排序),然后跑欧拉路径即可。

这道题中,因为我们要一个长为n+1的字符串满足n个字符对都出现过且仅出现一次,那我们就相当于是把每个字符对看成一条边,在这个图上求欧拉路径(回路),所以一开始要先判定它能否有欧拉路径(回路),之后就正常dfs。

对于起始点的选择有些神奇。我们不是每次都取最小的就行,因为如果要是求欧拉路径的话,我们必须强制选编号最小的奇点开始,如果要是求欧拉回路直接从最小的点开始即可。

这种题其实用邻接矩阵方便……而且好像这个数据范围邻接矩阵和邻接表跑的一样快。

看一下代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')

using namespace std;
typedef long long ll;
const int M = 20005;
const int INF = 1000000009;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
    if(ch == '-') op = -1;
    ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
    ans *= 10;
    ans += ch - '0';
    ch = getchar();
    }
    return ans * op;
}

struct edge
{
    int next,to,from,id;
    bool operator < (const edge &g) const
    {
        if(from != g.from) return from < g.from;
        else return to > g.to;
    }
}e[M<<1],q[M<<1];

int n,head[M],x,y,z,deg[M],ecnt = 1,minn = 100000,mpos = 100000,cnt,ans[M],tot;
char s[10];
bool vis[M];

void add(int x,int y,int z)
{
    e[++ecnt].to = y;
    e[ecnt].next = head[x];
    e[ecnt].id = z;
    e[ecnt].from = x;
    head[x] = ecnt;
}

void dfs(int x)
{
    for(int &i = head[x];i;i = e[i].next)
    {
    int k = e[i].to,j = e[i].id;
    if(!vis[j])
    {
        vis[j] = 1;
        dfs(k);
        ans[++cnt] = k;
    }
    }
}

int main()
{
    n = read();
    rep(i,1,n)
    {
    scanf("%s",s);
    q[i].from = q[i+n].to = s[0] - 'A' + 1;
    q[i].to = q[i+n].from = s[1] - 'A' + 1;
    q[i].id = q[i+n].id = i;
    }
    sort(q+1,q+1+(n<<1));
    rep(i,1,n<<1)
    {
    x = q[i].from,y = q[i].to,z = q[i].id;
    add(x,y,z),deg[x]++,deg[y]++;
    }
    //rep(i,1,100) printf("%d ",deg[i]);enter;
    rep(i,1,100) if((deg[i]>>1)&1) tot++;
    if(tot > 2)
    {
    printf("No Solution\n");
    return 0;
    }
    rep(i,1,100) if(i < mpos && (deg[i]>>1) & 1) mpos = i;
    if(mpos == 100000) ans[++cnt] = q[1].from,dfs(q[1].from);
    else ans[++cnt] = mpos,dfs(mpos);
    if(cnt != n+1) printf("No Solution\n");
    else
    {
    printf("%c",ans[1]+'A'-1);
    per(i,cnt,2) printf("%c",ans[i]+'A'-1);
    }
    return 0;
}

 

posted @ 2018-10-10 07:34  CaptainLi  阅读(318)  评论(0编辑  收藏  举报