思路是用map来存储,既然要求重名的条件是全排列,那么就设计一个不考虑字符顺序的散列函数。
最初是设计的用一个map存放各个字符出现的次数,stl容器是可以用!=来比较的,可以直接把它当作key,然后用map统计出现的次数。
map的[]运算符访问到不存在的元素会自动创建,利用了这点。题目本身其实很简单。
C++语言源码
#include <iostream>
#include <map>
#include <cstring>
using namespace std;
using Name=map<char,int>;
map<Name,int>mp;
int main()
{
int i,n;
cin>>n;
cin.get();
for(i=0;i<n;++i){
int temp;
Name tname;
while(isalpha(temp=getchar()))
++tname[temp];
printf("%d\n",mp[tname]++);
}
return 0;
}
上面代码大概用了四五百MS。。。。。。
然后尝试优化,用自定义的Name类代替Name map。
用一个数组来存放A到z的ASCII码出现的次数,因为是最多40个字,所以用char完全足够。(后来意外发现hdu系统的从'A'<=x<'Z'就可以,没有小写字母,缩短范围能有效缩短代码执行时间,其他的没测试,不知是不是弱数据)时间缩短一半多。
#include <iostream>
#include <map>
#include <cstring>
using namespace std;
class Name{
private:
char NameCount['Z'+1];
public:
Name(){
int i;
for(i='A';i<='Z';++i)
NameCount[i]=0;
}
char & operator [](int i){
return NameCount[i];
}
const bool operator <(const Name & that)const{
int i;
for(i='A';i<='Z';++i){
if(NameCount[i]<that.NameCount[i])
return true;
else if(NameCount[i]>that.NameCount[i])
return false;
}
return false;
}
const bool operator ==(const Name & that)const{
int i;
for(i='A';i<='Z';++i){
if(NameCount[i]!=that.NameCount[i])
return false;
}
return true;
}
const bool operator !=(const Name & that)const{
return !operator ==(that);
}
};
map<Name,int>mp;
int main()
{
int i,n;
cin>>n;
cin.get();
for(i=0;i<n;++i){
int temp;
Name tname;
while(isalpha(temp=getchar()))
++tname[temp];
printf("%d\n",mp[tname]++);
}
return 0;
}