BestCoder Round #92 1001 Skip the Class —— trie树 or map容器

题目链接: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;  
}  



2.map容器

其实做题时想到用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;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值