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()操作用位置做参数返回true
if ( 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 位设为1
00000000000000001111111111111111
//下面的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 而其他位保持为0
bitvec.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 1300


int64 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);
        }
    }
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值