zoj 3462 Nobita's New Filesystem (模拟题_Bitset应用)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4227
题目大意: 给定n个文件夹,每个文件夹有若干tag和一个size。再给出m个查询,查询也是若干个tag,要求找出这些tag在n个文件夹中的哪些里面出现,可以无视tag的顺寻,凡出现的都把size加起来,然后输出。
解题思路:用bitset和map能很轻松地解决,用个map记录每个tag在哪些文件夹中出现,map<string,bitset<1024> >(4>和>之间要有个'_'),表示1024个文件夹哪个包含这个string,然后查询的时候就只要看哪个文件夹包含了所有tag,也就是这些tag对应的bitset值&起来,到最后是true的那个文件夹就要把size累加起来。
先来看看百度百科上对bitset的一些介绍:
#include <bitset>bitset //有三种声明方式在缺省定义中我们只需简单地指明位向量的长度例如bitset< 32 > bitvec; //声明了一个含有32 个位的bitset 对象位的顺序从0 到31 缺省情况下所有的位都被 //对象的一位或多个位被设置为1 时any()返回true 对于bitvec .如下测试bool is_set = bitvec.any(); //它的结果当然是false 相反如果bitset 对象的所有位都被设置为0 ,则none()操作返回bool is_not_set = bitvec.none();//结果为true count()操作返回被设置为1 的位的个数.int bits_set = bitvec.count(); //我们可以用set()操作或者下标操作符来设置某个单独的位例如下面的for 循环把偶数位设置为1.for ( int index = 0; index < 32; ++ index ) if ( index % 2 == 0 ) bitvec[ index ] = 1; //类似地测试某个单独的位是否为1 也有两种方式test()操作用位置做参数返回trueif ( bitvec.test( 0 )) // 我们的bitve[0] 可以工作了! 同样地我们也可以用下标操作符for ( int index = 0; index < 32; ++index ) if ( bitvec[ index ] ) cout << index << " "; cout << endl;bitvec.reset( 0 );bitvec[ 0 ] = 0;//我们也可以用set()和reset()操作将整个bitset 对象的所有位设为1 或0 ,只要调用相应的操作而不必传递位置参数我们就可以做到这一点.例如bitvec.reset();if ( bitvec.none() != true )//flip()操作翻转整个bitset 对象或一个独立的位bitvec.flip( 0 ); // 翻转第一位bitvec[0].flip(); // 也是翻转第一位bitvec.flip(); // 翻转所有的位的值//还有两种方法可以构造bitset 对象它们都提供了将某位初始化为1 的方式:一种方法是为构造函数显式地提供一个无符号参数bitset 对象的前N 位被初始化为参数的相应位值,例如bitset< 32 > bitvec2( 0xffff );//将bitvec2 的低16 位设为100000000000000001111111111111111//下面的bitvec3 的定义bitset< 32 > bitvec3( 012 );//将第1 和3 位的值设置为1 假设位置从0 开始计数00000000000000000000000000001010//我们还可以传递一个代表0 和1 的集合的字符串参数来构造bitset 对象如下所示// 与bitvec3 的初始化等价string bitval( "1010" );bitset< 32 > bitvec4( bitval );//bitvec4 和bitvec3 的第1 和3 位都被设置为1 而其他位保持为0bitvec.set()看完这些,在对照着题目和代码,就会发现用bitset还是相当飘逸的。
测试数据:
5
[comic][naruto][01] 1024
[comic][naruto][02] 1024
[comic][inuyasha][01] 1024
[comic][inuyasha][02] 1024
[comic][inuyasha][03] 1024
3
[inuyasha]
[comic][01]
[ost]
Out: 3072 \n 2047\n 0\n
代码:
#include <cstdio>#include <map>#include <string>#include <cstring>#include <bitset>#include <vector>using namespace std;#define int64 long long#define MAX 1300int64 n,m,size[MAX],ans;bitset<MAX> mask; //mask表示该串出现在哪些主串中char str[1<<17],*p,*q;map<string,bitset<MAX> > mmap; //表示i=0...n-1内哪些串含有string子串map<string,bitset<MAX> >::iterator it; //迭代器int main(){ int i,j,k; while (scanf("%lld",&n) != EOF) { ans = 0; mmap.clear(); for (i = 0; i < n; ++i) { scanf("%s %lld",str,&size[i]); p = str; //把首地址付给p指针 while ((p = strchr(p,'[')) != NULL) { //从p开始找第一个'[',如果没有返回NULL q = strchr(p,']'); string tp = string(p+1,q); //构造函数tp = str[p+1........q-1] mmap[tp].set(i); //第i个串含有tp p = q; //从q开始才不至于无限循环 } } scanf("%lld",&m); for (i = 0; i < m; ++i) { scanf("%s",str); for (j = 0; j < n; ++j) mask.set(j); //相当于memset(true) p = str; while ((p = strchr(p,'[')) != NULL) { q = strchr(p,']'); string tp = string(p+1,q); it = mmap.find(tp); //相当于mmap[tp] if (it == mmap.end()) { mask.reset(); break; } else mask &= it->second; //如果it里都有某位,则最后该子串必定包含在那个主串中 p = q; } ans = 0; for (j = 0; j < n; ++j) if (mask[j]) ans += size[j]; printf("%lld\n",ans); } }}