这个主要就是一个集合的交-差问题.由于数据量比较大,考虑用 STL 里面的SET 来当数据结构,存储每个单词出现的文档编号.我的思路是,找到一个为 1 的单词的下标,把这个单词的文档编号输出到 res 中,然后遍历,遇到0,什么也不做;遇到-1,就判断res中是否有这些文档,如果有,就删除;遇到1,就取交集,这里可以用一个 temp set集合来存储公共元素.(或者直接用两个迭代器在两个SET里面遍历,由于是递增排列的,删除非公共元素很方便,这里不做讨论)
描述
现在已经对一些文档求出了倒排索引,对于一些词得出了这些词在哪些文档中出现的列表。
要求对于倒排索引实现一些简单的查询,即查询某些词同时出现,或者有些词出现有些词不出现的文档有哪些。
输入
第一行包含一个数N,1 <= N <= 100,表示倒排索引表的数目。
接下来N行,每行第一个数ci,表示这个词出现在了多少个文档中。接下来跟着ci个数,表示出现在的文档编号,编号不一定有序。1 <= ci <= 1000,文档编号为32位整数。
接下来一行包含一个数M,1 <= M <= 100,表示查询的数目。
接下来M行每行N个数,每个数表示这个词要不要出现,1表示出现,-1表示不出现,0表示无所谓。数据保证每行至少出现一个1。
输出
共M行,每行对应一个查询。输出查询到的文档编号,按照编号升序输出。
如果查不到任何文档,输出"NOT FOUND"。
样例输入
3
3 1 2 3
1 2
1 3
3
1 1 1
1 -1 0
1 -1 -1
样例输出
NOT FOUND
1 3
1
#include <iostream>
#include <stdio.h>
#include <set>
using namespace std;
int n, num, t;
int query[110];
set<int> s[200];
set<int> res;
set<int>::iterator it;
set<int>::iterator it2;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&num);
while(num--)
{
scanf("%d",&t);
s[i].insert(t);//保存每个单词出现的文档
}
}
scanf("%d",&num);
while(num--)
{
int _index = 0, flag = 0;
for(int i=1;i<=n;i++)
{
scanf("%d",&query[i]);
if(query[i] == 1)
_index = i;//找到这个单词的下标
}
//初始化 res
for(it=s[_index].begin();it!=s[_index].end();it++)
res.insert(*it);
for(int i=1;i<=n;i++)
{
if(query[i] == 1)//取交集
{
set<int> temp;
it = s[i].begin();
for(;it!=s[i].end();it++)
{
it2 = res.find(*it);
if(it2 != res.end())
{
temp.insert(*it);
}
}
if(temp.empty())
{
flag = 1; break;//没有公共元素,不需要再做下去,直接中断循环
}
else
{//更新 res
res.clear();
it = temp.begin();
while(it != temp.end())
{
res.insert(*it);
it++;
}
}
}
else if(query[i] == -1)//删掉这些元素
{
it = s[i].begin();
for(;it!=s[i].end();it++)
{
it2 = res.find(*it);
if(it2 != res.end())
res.erase(*it);
}
}
}
if(flag==1 || res.empty())
printf("NOT FOUND\n");
else
{
for(it=res.begin();it!=res.end();it++)
printf("%d ",*it);
printf("\n");
}
}
return 0;
}