4 //t组样例
3 5 //3个集合,5个点
2 2 1 //2大小,覆盖点2和点1
1 4 //1大小,覆盖点4
2 3 5 //2大小,覆盖点3和点5
3 3 //3个集合,3个点
3 1 2 3 //3大小,覆盖点1和点2和点3
3 2 3 1 //3大小,覆盖点2和点3和点1
3 3 1 2 //3大小,覆盖点3和点1和点2
3 3
2 1 2
2 2 3
2 3 1
3 3
2 2 3
1 1
2 1 3
Sample Output
3
1 2 3
1
1
2
1 2
2
1 2
一个很容易想到的做法:
#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<cmath>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define ll long long
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int n,m,a,b;
cin>>n>>m;
int minn=100000000,p;
for(int i=0;i<n;++i){
cin>>a;
for(int j=0;j<a;++j){
cin>>b;
y[i].push_back(b);
}
}
for(int i=1;i<(1<<n);++i){
map<int,int> r;
for(int j=0;j<n;++j){
if(i&(1<<j)){
for(int k=0;k<y[j].size();++k){
r[y[j][k]]=1;
}
}
}
if(r.size()==m){
......
}
}
......
}
return 0;
}
但是复杂度会爆。所以用下面的做法:
#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<cmath>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define ll long long
using namespace std;
int x[65];
int main(){
int t;
cin>>t;
while(t--){
memset(x,0,sizeof(x));
int n,m,a,b;
cin>>n>>m;
int minn=100000000,p;
for(int i=0;i<n;++i){
cin>>a;
for(int j=0;j<a;++j){
cin>>b;
x[b]|=(1<<i);
}
}
for(int i=1;i<(1<<n);++i){
int w=0,h=i,s=0;
while(h>0){
w+=h%2;
h/=2;
}
for(int j=1;j<=m;++j){
if(x[j]&i) //如果i里面包含至少一个有j的位
s++;
}
if(s==m){
if(w<minn){
minn=w;
p=i;
}
}
}
cout<<minn<<endl;
int s=1,w=1;
while(p>0){
if(p%2==1){
if(s<minn)
cout<<w<<" ";
else
cout<<w<<endl;
s++;
}
p/=2;
w++;
}
}
return 0;
}