题意:
现在有n盏灯,每开关控制了一些灯,按一下这些灯的状态就会翻转。现在每次有一些灯开着,问你让所有灯熄灭的最少需要按的开关数量是多少。
题解:
那么这道题目的开关数只有30,很容易想到折半搜索,但是开关数有1000个,就算用了bitset运算,时间复杂度也是不够的,但是我们可以知道,起始状态是固定的,那么我们只需要这个折半偏一点点,起始状态给个20个开关,然后每次只需要搜后面10个开关,时间复杂度就允许了。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5,M=(1<<20)+5,K=(1<<10)+5;
unordered_map<bitset<N>,int>mp;
bitset<N>b[N],tmp,tt;
int main()
{
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=0;i<m;i++){
int k,x;
scanf("%d",&k);
while(k--){
scanf("%d",&x);
b[i].set(x);
}
}
int num=min(m,20),mx=(1<<num)-1;
//mp[0]=0;
for(int i=0;i<=mx;i++){
tmp.reset();
int sum=0;
for(int j=0;j<num;j++){
if(i&(1<<j)){
tmp^=b[j];
sum++;
}
}
if(!mp.count(tmp)||mp[tmp]>sum)
mp[tmp]=sum;
}
while(q--){
int k,x;
scanf("%d",&k);
tmp.reset();
while(k--){
scanf("%d",&x);
tmp.set(x);
}
if(m<=20){
if(mp.count(tmp))printf("%d\n",mp[tmp]);
else printf("-1\n");
continue;
}
num=m-20,mx=(1<<num)-1;
int ans=N;
for(int i=0;i<=mx;i++){
tt=tmp;
int sum=0;
for(int j=0;j<num;j++){
if(i&(1<<j)){
tt^=b[j+20];
sum++;
}
}
if(mp.count(tt))
ans=min(ans,mp[tt]+sum);
}
printf("%d\n",ans==N?-1:ans);
}
return 0;
}