题目:http://acm.hdu.edu.cn/showproblem.php?pid=1800
给出一堆士兵的等级,等级高的的士兵可以当等级小的士兵的师傅,一个士兵最多一个师傅(可以没有),一个师傅最多1个徒弟(可以没有),如果是师徒关系,可以用一把扫帚练习技能,问:全部士兵都用扫帚练习时需要的最少的扫帚数量?
这就是寻找一棵树的最大分支嘛,如果所有的数字均不相同那么必能连成一串,仅需一把扫帚,多一个重复的元素就要多一把扫帚,所以就是统计数字的最大重复次数。再次涉及到统计了。。能用字典树解决,同样也能用映射解决,当然map的思想来源于hash。
trie(运行时间:374MS):
#include <iostream> #include<cstdio> using namespace std; int result; typedef struct node{ int num; bool fina; struct node *next[10]; }*trie,node; trie root; void init(trie &p){ p=new node(); for(int i=0;i<10;i++)p->next[i]=0; p->num=p->fina=0; } void insert(char s[]){ trie p=root; int k=0; while(s[k]=='0')k++; while(s[k]){ if(p->next[s[k]-'0']==0){ trie q; init(q); p->next[s[k]-'0']=q; } p=p->next[s[k]-'0']; k++; } p->num++; p->fina=1; result=result>p->num?result:p->num; } int main() { //freopen("cin.txt","r",stdin); int n; while(cin>>n){ result=0; char s[35]; init(root); for(int i=0;i<n;i++){ scanf("%s",s); insert(s); } printf("%d\n",result); } return 0; }映射统计(运行时间:717MS):
#include <iostream> #include<map> #include<cstdio> using namespace std; int main() { //freopen("cin.txt","r",stdin); int n,result; while(cin>>n){ result=0; map<int,int> mp; for(int i=0;i<n;i++){ int t; scanf("%d",&t); mp[t]++; result=result>mp[t]?result:mp[t]; } printf("%d\n",result); } return 0; }最开始时自己惯性的用字符串和整数构成映射关系,结果,出现各种问题:
//////////////////////////////////////////////////////////////////////////
超时可能在于mp的内部排序,干脆不排序了,--> WA:
#include <iostream>
#include<map>
#include<cstring>
#include<cstdio>
using namespace std;
char s[3005][35];
int main()
{
freopen("cin.txt","r",stdin);
int n,result;
while(cin>>n){
result=0;
//map<char *,int,cmp> mp;
map<char *,int> mp; //不排序的映射导致即使重复出现,次数也记为1
for(int i=0;i<n;i++){
scanf("%s",s[i]);
int k=0;
while(s[i][k]=='0')k++;
mp[s[i]+k]++;
result=result>mp[s[i]+k]?result:mp[s[i]+k];
}
for(map<char *,int>::iterator ix=mp.begin();ix!=mp.end();ix++){
cout<<ix->first<<" "<<ix->second<<endl;
}
printf("%d\n",result);
}
return 0;
}
同时也能看出,字典树在数据多和数据长度长后在时间复杂度上的优势。
hash的相关函数ELFhash是我开始学习时比较头疼的事儿,看了半天都没看懂。这是我看别人的讲解:
// ELF Hash Function
unsigned int ELFHash(char *str)
{
unsigned int hash = 0;
unsigned int x = 0;
while (*str)
{
hash = (hash << 4) + (*str++);//hash左移4位,当前字符ASCII存入hash低四位。
if ((x = hash & 0xF0000000L) != 0)
{//如果最高的四位不为0,则说明字符多余7个,如果不处理,再加第九个字符时,第一个字符会被移出,因此要有如下处理。
//该处理,如果对于字符串(a-z 或者A-Z)就会仅仅影响5-8位,否则会影响5-31位,因为C语言使用的算数移位
hash ^= (x >> 24);
//清空28-31位。
hash &= ~x;
}
}
//返回一个符号位为0的数,即丢弃最高位,以免函数外产生影响。(我们可以考虑,如果只有字符,符号位不可能为负)
return (hash & 0×7FFFFFFF);
}
多多实践理解会更加深入的。
hash(运行时间:124MS)
#include <iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=7000; int hashx[maxn],countx[maxn],n,result; int ELFhashx(char *key){ unsigned long h=0,g; while(*key){ //一个字符需要用8位来表示,2^9-1=511. 2^4-1=15用四位只存储了字符的一半的信息。 h=(h<<4)+*key++; //低四位存入字符 g=h&0xf0000000L; //g即是取h的二进制高4位,第8个字符的信息 if(g) h^=g>>24; //一个英文字符一个字节8位,英文字符ASCII:97--122.如果g是非0的,代表这是第8个字符 h&=~g; } return h&0x7fffffff; } void hashxit(char *s){ int k; while(*s=='0') s++; k=ELFhashx(s); int t=k%maxn; while(hashx[t]!=k&&hashx[t]!=-1){ t=(t+10)%maxn; } if(hashx[t]==-1){ countx[t]=1; hashx[t]=k; } else if(++countx[t]>result)result=countx[t]; } int main() { //freopen("cin.txt","r",stdin); char str[100]; while(cin>>n){ memset(hashx,-1,sizeof(hashx)); getchar(); result=1; for(int i=0;i<n;i++){ gets(str); hashxit(str); } cout<<result<<endl; } return 0; }没想到hash比字典树还要快啊,哈哈哈,我想这可能和字典树的链式结构相关。