题目名称:度度熊与排列
题目链接:
Problem Description
度熊有一个机器,这个机器有一个1~M 的排列 p [ 1.. M ] p[1..M] p[1..M] 当作参数,若丢进一个长度为 M M M 的字符串,此机器会将此字符串重新排列后再输出,重新排列的方式为:原本第 i个位置的字符会变到第 p [ i ] p[i] p[i] 个位置。
举例来说,当 M M M=3,p[1]=3,p[2]=1,p[3]=2那么丢 “abc” 进入这个机器后,机器会输出"bca";若丢进的是 “ded”,那么机器会输出 “edd”。
某天,度熊不小心忘记这个机器的参数了,只记得参数的长度是 M M M,于是他丢了 N N N长度为 M M M 的字符串进去,并记录下对于每个字符串机器的输出结果,请你根据这些结果,帮度熊找回这个机器的参数。若有多组参数都满足度熊的记录,请输出字典序最小的排列作为参数。若并不存在任何参数满足度熊的记录,请输出 −1。
注:对于两个相异的排列a: a [ 1.. M ] a[1..M] a[1..M] 和 b [ 1.. M ] b[1..M] b[1..M],我们称 a 比 b 小当且仅当 存在一个 i,满足对于所有小于 i 的 j 都有 a j = b j a_j=b_j aj=bj 且 a i < b i a_i < b_i ai<bi。
Input
有多组询问,第一行包含一个正整数 T T T 代表有几组询问。
每组询问的第一行包含两个正整数 N , M N,M N,M,分别代表度熊丢进机器的字符串数目以及参数的长度。接下来还有 2 × N 2×N 2×N行,每行有一个长度为 M M M 的字符串,当中的第 2 × i − 1 2×i−1 2×i−1 行的字符串代表度熊丢进去机器的第 i i i 个字符串,而第 2 × i 2×i 2×i 行的字符串代表机器对于第 iii 个字符串的输出结果。
1 ≤ T ≤ 100 1≤T≤100 1≤T≤100
1 ≤ N ≤ 20 1≤N≤20 1≤N≤20
1 ≤ M ≤ 50 1≤M≤50 1≤M≤50
字符串由英文小写字母(‘a’ 至 ‘z’) 组成
Output
对于每一个询问,输出一行,若不存在任何参数满足度熊的记录,这行只包含一个整数 − 1 −1 −1。否则这行包含一个排列,代表此机器所有可能的参数中字典序最小的那个。
Sample Input
4
1 3
abc
bca
2 4
aaab
baaa
cdcc
cccd
3 3
aaa
aaa
bbb
bbb
ccc
ccc
1 1
a
z
Sample Output
3 1 2
2 4 3 1
1 2 3
-1
解题思路
第一眼看过去就是简单的字符串位置变换,就匆匆写完提交了,Worry Answer,然后仔细审题才发现第二组数据有多个输入,思考以后决定使用Map<int,int> mp[60]这个函数来判断,对于第
i
i
i次输入 mp[i]存储丢进的字符串M在对应串中每个字符可能的位置
如下:
aaab
baaa
则 第一个字符a对应的可能位置为 2,3,4
第二个字符a对应的可能位置为2,3,4
第三个字符a对应的可能位置为2,3,4
第四个字符对应的可能位置为1
接下来是第二组输入
cdcc
cccd
第一个字符c对应的可能位置为1,2,3
第二个字符d对应的可能位置为4
第三个字符c对应的可能位置为1,2,3
第四个字符对应的可能位置为1,2,3
几次输入完成后会得到如下结果
以第一个字母为例子:
位置 1 映射次数 1次
位置 2 映射次数 2次
位置 3 映射次数 2次
位置 4 映射次数 1次
检索出现次数的最大值且第一次出现的位置,于是判断 字符a出现位置为2
同理 得出编码顺序 2 4 3 1
mark数组作为标记,防止同样的字母在已经被映射的位置再次被映射,可以继续查找下一个合适的位置
使用chec函数来判断字符串是否符合题目条件,符合则执行接下来步骤,不符合直接输出-1
完整代码
#include<iostream>
#include<string>
#include<map>
#include<cstdio>
#include<cstring>
using namespace std;
int t,n,m;
string s1,s2;
int table[30],mark[60];
map<int,int> mp[60];
bool flag;
void check(){
for(int i=0;i<m;i++){
for(int j=0;j<m;j++){
if(s1[i]==s2[j]){
mp[i][j]++;
}
}
}
}
void chec(){ // 判断是否符合提意
if(flag==false){
return ;
}
memset(table,0,sizeof(table));
memset(mark,0,sizeof(mark));
for(int i=0;i<m;i++){
mark[s1[i]-'a']++;
}
for(int i=0;i<m;i++){
table[s2[i]-'a']++;
}
for(int i=0;i<27;i++){
if(mark[i]!=table[i]){
flag=false;
return ;
}
}
}
int main()
{
// freopen("in.txt","r",stdin);
cin>>t;
while(t--){
for(int i=0;i<60;i++) mp[i].clear();
cin>>n>>m;
cin.ignore();
flag=true;
for(int i=0;i<n;i++){
cin>>s1>>s2;
check();
chec();
}
memset(mark,0,sizeof(mark));
int maxV,ind;
// first 坐标 second 次数
if(flag){
for(int i=0;i<m;i++){
maxV=0;
ind=0;
for(map<int,int>::iterator it=mp[i].begin();it!=mp[i].end();it++){
if(maxV<it->second&&!mark[it->first+1]){
maxV=it->second;
ind=it->first+1;
}
}
mark[ind]=1;
if(i!=m-1) cout<<ind<<' ';
else cout<<ind<<endl;
}
}else{
cout<<"-1"<<endl;
}
}
return 0;
}