2664 字母表

原题链接

2664 字母表

题目大意

n ( 1 ≤ n ≤ 100 ) n(1\le n\le 100) n(1n100) 个单词,需要你设置一种字典序,让这些单词按照题目所给的顺序进行排序。

解题思路

比较好想的一种做法就是先建边,再进行拓扑排序。拓扑排序简单,只需要使用板子即可,但是建边就比较难了(调了一个上午!!!)。
如何建边?先看一个例子:

3
rivest
shamir
adleman

先从第一位建起:

3
r|ivest
s|hamir
a|dleman

为了让它们按照这个顺序排列,就要保证在字典序中: r < s < a r<s<a r<s<a,因为只要满足这个条件,就可以拍好序,所以,排完了。但是,如果出现开头相同:

3
r|ivest
s|hamir
s|dleman

这时,我们先通过开头一位可以确定 r < s r<s r<s 。但在确定最后两个单词时,就需要比较第二位:

3/*
r|ivest*/
s|h|amir
  ^
s|d|leman
  ^

接着我们就可以得到 h < d h<d h<d
最后还要注意两点:

  1. 当只有长度不同时(以防以下情况Impossible)
3
aaaaaaa
aaaa
a
  1. 每次要建多条边(以防以下情况没有Impossible)
5
ab
cb
db
ed
ea

代码实现

#include<iostream>
#include<map>
#include<cstring>
#include<vector>
#include<stack>
using namespace std;
int n,max_len,ans,N=1;
char px[110],q[110];
string s[110];
bool v[110];
map<char,vector<char> > e;
map<char,int> Map;
map<char,bool> ans_v,ans_v2;
void bfs()//拓扑排序(板子)
{
	int t=0,h=0;
	for(int i=0;i<26;i++)
		if(!Map[char(i+'a')]){
			q[++t]=char(i+'a');
			px[++ans]=char(i+'a');
		}
	while(h<t){
		h++;
		char now=q[h];
		for(int i=0;i<e[now].size();i++){
			Map[e[now][i]]--;
			if(!Map[e[now][i]]){
				q[++t]=e[now][i];
				px[++ans]=e[now][i];
			}
		}
	}
}
void make_edge(int l,int r,int p)//建边
{
	if(p>max_len-1)
		return;
	int l2=l,r2=l;
	vector<char> now;
	for(int i=l;i<r;i++){
		if(s[i][p]==s[i+1][p])
			r2=i+1;
		else{
			if(s[i][p]!=' ')
			{
				now.push_back(s[i][p]);
				make_edge(l2,r2,p+1);//递归
			}
			l2=i+1;
		} 
	}
	if(s[r][p]!=' '){
		now.push_back(s[r][p]);
		make_edge(l2,r,p+1);
	}
	for(int i=0;i<now.size();i++){//每两点建一条边,枚举第一点
		for(int j=i+1;j<now.size();j++){//每两点建一条边,枚举第二点
			e[now[i]].push_back(now[j]);//建边
			Map[now[j]]++;//累加入度
		}
	}
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>s[i];
		max_len=max(max_len,(int)s[i].size());
	}
	for(int i=1;i<n;i++){//特判长度
		if(s[i].size()>s[i+1].size()&&s[i].substr(0,s[i+1].size())==s[i+1]){
			cout<<"Impossible";
			return 0;
		}
	}
	for(int i=1;i<=n;i++){//统一长度
		if(s[i].size()<max_len){
			int len=s[i].size();
			for(int j=1;j<=max_len-len;j++)
				s[i]+=" ";
		}
	}
	make_edge(1,n,0);
	bfs();
	if(ans!=26)
		cout<<"Impossible";
	else{
		for(int i=1;i<=ans;i++)
			cout<<px[i];
	}
	return 0;
}

样例1

输入

3
rivest
shamir
adleman

样例2(点13)

答案不唯一,可自行排序(非Impossible)

输入

20
jtjdxwguinrfqc
nayyakdmpf
dauemwdqilc
gerrqwvmqye
x
xgq
owixhphzh
ofcvwucgekbafr
aitdmozzauatr
eydxwjh
bmoexdnvbetb
fxtkzvf
frjdsldludgojnh
uqf
lmmrgyshzphefgifw
pajrijnnkor
viczzuevgcxpjxplwo
q
qtksab
cxovltrozgyisqhpityx

输出

答案不唯一,可自行排序(非Impossible)

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值