题目链接:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=748&pid=1001
题解:
1.trie树
关键是如何将科目与分数进行对应,即如果将字符串与数字对应。由于之前解除了字典树,所以就想到用字典树存储单词,并为每种编上编号,之后就用这个编号与分数对应。
就个人观点而言,a[][]数组应该不用清零,因为下个case会将之前的case覆盖掉,但是错了,也找不出原因。所以以后为了安全起见,不管是否会被覆盖,都清零吧,这样保险一点。
代码如下:
#include<bits/stdc++.h>//字典树
using namespace std;
int a[105][105],deg[105], b[105],vis[105],sum;
//a[][]记录单词的值,从1开始记录。deg[]记录单词有多少个值。sum为单词的种数。
typedef struct node//字典树的结点
{
struct node *next[26];
int pos;
}Trie, *PT;
int init(PT &p)//初始化结点
{
p = (PT)malloc(sizeof(Trie));
p->pos = 0;
for(int i = 0; i<26; i++)
p->next[i] = NULL;
}
//访问字典树,若果单词已存在,则返回这个单词的编号,如果不存在,则编号加1,并返回。
int trie(char *s, int k, PT &p)
{
if(!s[k])
{
if(p->pos) return p->pos;
p->pos = ++sum;
return p->pos;
}
else
{
if(!p->next[s[k]-'a'])
init(p->next[s[k]-'a']);
return trie(s,k+1,p->next[s[k]-'a']);
}
}
int cmp(int a,int b)
{
return a > b;
}
int main()
{
int T,n,val,ans;
char s[15];
PT p;
scanf("%d",&T);
while(T--)
{
init(p);
scanf("%d",&n);
ans = 0; sum = 0;
memset(deg,0,sizeof(deg));
memset(vis,0,sizeof(vis));
memset(a,0,sizeof(a));//为什么少了这步会出错,这步好像不是必要的吧?
for(int i = 0; i<n; i++)
{
scanf("%s%d",s,&val);
b[i] = trie(s,0,p);//获取单词的编号,并将其储存到b[]中,
a[b[i]][deg[b[i]]++] = val;//更新a数组和deg数组
}
for(int i = 0; i<n; i++)
{
if(!vis[b[i]])//如果没有访问编号为b[i]的单词,则访问。
{ //对这个单词的值进行排序,选其前二,并标为已访问。
sort(a[b[i]],a[b[i]]+deg[b[i]],cmp);
vis[b[i]] = 1;
ans += a[b[i]][0] + a[b[i]][1];
}
}
printf("%d\n",ans);
}
return 0;
}
其实做题时想到用c++的map会很方便,只可惜没有学map的操作。也好,现在补回来了。
对于map的认识:
1.map一个key只能对应一个val,而multimap一个key能对应多个val。所以如果对map的key进行多次复制,其旧val会被新val覆盖。而multimap则插入新的val。
2.由于map一对一,所以可以直接用map[key] = val,以数组的形式直接赋值,而multimap则只能用map.insert(pair<string,int>("ss",11))进行插入赋值。
3.要访问元素要使用迭代器map<string,int>::iterator it,last; 4
4.两种map都自动根据key值进行递增排序。
代码如下:
#include<bits/stdc++.h>
#define MAX(a,b) (a>b?a:b)
using namespace std;
int main()
{
int n,val,T;
char s[15];
map<string,int> m1,m2;
map<string,int>::iterator it,last;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
m1.clear(); m2.clear();//清空map
for(int i = 0; i<n; i++)
{
scanf("%s%d",s,&val);
//更新第一二大值
m2[s] = MAX(m2[s],val);
if(m1[s]<m2[s]) swap(m1[s],m2[s]);
}
int ans = 0;
for(it = m1.begin(),last = m1.end(); it!=last; it++)
ans += it->second;
for(it = m2.begin(),last = m2.end(); it!=last; it++)
ans += it->second;
printf("%d\n",ans);
}
return 0;
}