POJ2337 Catenyms

本文介绍如何解决一个特定问题:通过判断一组单词是否能首尾相连形成一个连续字符串,并输出字典序最小的欧拉路径。采用深度优先搜索(DFS)策略构建路径,同时确保最终路径字典序最小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门


题目大意:
判断单词能否首尾相连构成一个串,如果可以输出字典序最小的方案


和POJ1386一样,只不过这道题需要输出欧拉路径,并且是最小字典序(怎么判断就不说了,详细讲解请见POJ1386)
先忽略字典序最小这个问题……..
我们求欧拉路径用的当然是dfs,当我们dfs的时候发现有一个点无路可走了,那么我们回溯,把来时的边压入栈中,然后重复这个过程,最后我们遍历完所有边之后,把栈中的边依次弹出,得到的就是欧拉路径,至于正确性,你自己手动模拟一遍就理解了
然后考虑怎么让字典序最小
把这些单词(也就是这些边)按照字典序从大到小排序,字典序大的先建边,这样就保证了我们先访问到的一定是字典序较大的边,这条边也就先被压入栈中,后被弹出,所以得到的一定是字典序最小滴……..
以后一定记得好好检查数组下标问题……..今天因为吧rank[i]写成了i,WA了一下午QAQ好忧伤……………..


代码如下:
代码略长…………….

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define Min(a,b,c) min(a,min(b,c))
using namespace std;
const int maxn=1000+5;
char s[maxn][maxn];
int rank[maxn],cas,n,hd[30+5],cnt,in[30+5],out[30+5],S,stk[maxn],tail;
bool vis[maxn];
struct edge{
    int to,nxt,w,flag;
}e[maxn*2];
bool cmp(int a,int b){
    return max(0,strcmp(s[a],s[b]));
}
void add(int x,int y,int z){
    e[cnt].to=y;
    e[cnt].w=z;
    e[cnt].nxt=hd[x];
    e[cnt].flag=false;
    hd[x]=cnt++;
    in[y]++;
    out[x]++;
}
void dfs(int root){
    for(int i=hd[root];i!=-1;i=e[i].nxt)
        if(!e[i].flag){
            e[i].flag=true;
            dfs(e[i].to);
            stk[++tail]=e[i].w;
        }
}
bool checkdfs(){
    for(int i=0;i<cnt;i++)
        if(!e[i].flag)
            return false;
    return true;
}
bool check(){
    int la=0,lala=0,lalala=0,k;
    for(int i=1;i<=26;i++){
        if(out[i]-in[i]==1)
            lala++,S=i;
        if(in[i]-out[i]==1)
            la++;
        if(abs(out[i]-in[i])>1)
            lalala++;
    }
    if(la>1||lala>1||lalala>0)
        return false;
    return true;
}
signed main(void){
//  freopen("lala.in","r",stdin);
//  freopen("lala.out","w",stdout);
    scanf("%d",&cas);
    while(cas--){
        cnt=tail=0,S=1000;
        scanf("%d",&n);
        memset(hd,-1,sizeof(hd));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(vis,false,sizeof(vis));
        for(int i=1;i<=n;i++)
            scanf("%s",s[i]),rank[i]=i;
        sort(rank+1,rank+n+1,cmp); 
        for(int i=1,x,y,z;i<=n;i++)
            x=s[rank[i]][0]-'a'+1,y=s[rank[i]][strlen(s[rank[i]])-1]-'a'+1,add(x,y,rank[i]),S=Min(S,x,y);
        if(!check())
            cout<<"***"<<endl;
        else{           
            dfs(S);         
            if(!checkdfs())
                cout<<"***"<<endl;
            else{
                for(int i=tail;i>1;i--)
                    cout<<s[stk[i]]<<".";
                cout<<s[stk[1]]<<endl;
            }
        }
    }
    return 0;
}

by >o< neighthorn

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值