专栏文章

题解:AT_icpc2012autumn_a Dictionary

AT_icpc2012autumn_a题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miq8atga
此快照首次捕获于
2025/12/04 00:35
3 个月前
此快照最后确认于
2025/12/04 00:35
3 个月前
查看原文

题意

给定 nn 个字符串,判断是否有一种字典序使得它们按这种字典序排序。当 sstt 的前缀时,ss 应当排在 tt 前面。

解法

如果 sts \le t,要么 sstt 的前缀,或者有一个最小的 ii,使得 si<tis_i < t_i
用图论解决这个问题。
找到这个 iisis_itit_i 连一条边。由此构成一个有向图,uuvv 有边代表 u<vu<v。显然的,如果图中有环,那么环里的字母都大于且小于彼此,这样是无解的。
那么建完图之后暴力枚举从某个字母是否有一条路径能回到它自己,如果有则无解。
CPP
#include <bits/stdc++.h>
using namespace std;

const int maxn=5e2+5;
int n,e[26][26];
string a[maxn];
bool is,vis[26];
void fd(int fa,int u,bool o){//o是为了防止刚进去就被判到环
    if(u==fa && o){
        is=1;//找到环了
        return ;
    }
    for(int i=0;i<26;i++)
        if(!vis[i] && e[u][i]) 
            vis[i]=1,fd(fa,i,1);//往前走
}
bool solve(){
	memset(e,0,sizeof(e));
    for(int i=1;i<=n;i++) cin >> a[i];
    for(int i=1;i<n;i++){
        string s=a[i],t=a[i+1];
        bool f=1;
        for(int i=0;i<min((int)s.length(),(int)t.length());i++)
            if(s[i]!=t[i]){
            	e[s[i]-'a'][t[i]-'a']=1,f=0;//加边
            	break;
            }
        if(f && s.length()>t.length()) return 0;//s不等于t且t是s前缀
    }
    for(int i=0;i<26;i++){
        is=0;
        memset(vis,0,sizeof(vis));
        fd(i,i,0);
        if(is) return 0;
    }
    return 1;
}
int main(){
    while(scanf("%d",&n)){
    	if(!n) break;
    	if(solve()) puts("yes");
    	else puts("no");
    }
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...