大概就是选最少的人能打败所有人
然后把每个人能打败的人作为行,一共的人作为列重复覆盖
注意:自己是能打败自己的
DLX用起来挺简单的:
1.insert 插入行列,表示能覆盖
2.solve 二分找答案(感觉应该从小到大写 IDA*)
#include <cstdio>
#include <deque>
#include <set>
#include <string>
#include <map>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
typedef long long LL;
#define Debug(x) (cerr << #x << " = " << (x) << endl)
#define Debug2(x, y) (cerr << #x << " = " << (x) << ", " << #y << " = " << (y) << endl)
template<class T> inline T& RD(T &x){
char c; for (c = getchar(); c < '0'; c = getchar()); x = c - '0'; for (c = getchar(); '0' <= c && c <= '9'; c = getchar()) x = x * 10 + c - '0';
return x;
}
const int inf = 0x3f3f3f3f;
const int N = 256*256;
const int MAXN = 256;
const int MAXM = 256;
int L[N],R[N],U[N],D[N],nc[N],nr[N];
int col[MAXN],row[MAXM],sz[MAXN];
int head,eid,cn;
//id chazai h youmian
void linkLR(int &h, int &id){
L[R[h]] = id;
L[id] = h;
R[id] = R[h];
R[h] = id;
}
//id chazai h xiamian
void linkUD(int &h,int &id){
U[D[h]] = id;
U[id] = h;
D[id] = D[h];
D[h] = id;
}
void init(){
memset(nc,-1,sizeof(nc));
memset(col,-1,sizeof(col));
memset(row,-1,sizeof(row));
eid = 1,cn = 0;
L[head] = R[head] = U[head] = D[head] = head = 0;
}
void inr(int r){
linkUD(head,eid);
L[eid] = R[eid] = eid;
row[r] = eid ++;
}
void inc(int c){
linkLR(head,eid);
U[eid] = D[eid] = eid;
nc[eid] = c;
sz[c] = 0;
++ cn;
col[c] = eid ++;
}
void inm(int r,int c){
int rid = row[r],cid = col[c];
linkLR(rid,eid);
linkUD(cid,eid);
nc[eid++] = c;
++sz[c];
}
void insert(int r,int c){
if(col[c] == -1)inc(c);
if(row[r] == -1)inr(r);
inm(r,c);
}
void remove(int c){
int i,j;
for(i=D[c];i!=c;i=D[i]){
L[R[i]] = L[i];
R[L[i]] = R[i];
sz[nc[i]]--;
}
}
void resume(int c){
int i,j;
for(i=U[c];i!=c;i=U[i]){
L[R[i]] = i;
R[L[i]] = i;
sz[nc[i]] ++;
}
}
int cq(){
bool hash[MAXN];
int c,i,j,ret=0;
memset(hash,0,sizeof(hash));
for(c=R[head];c!=head;c=R[c]){
if(!hash[nc[c]]){
ret ++;
hash[nc[c]] = true;
for(i=D[c];i!=c;i=D[i]){
for(j=R[i];j!=i;j=R[j]){
if(nc[j] != -1){
hash[nc[j]] = true;
}
}
}
}
}
return ret;
}
//lim weisuoyaoqiude zuiyoujie
bool dfs(int d,int lim){
if(d+cq()>lim)return false;
if(R[head] == head)return true;
int i,j,c,maxx=1<<28;
for(i=R[head];i!=head;i=R[i]){
if(sz[nc[D[i]]] < maxx){
maxx = sz[nc[D[i]]];
c = i;
}
}
int key = 0;
for(i=D[c];i!=c;i=D[i]){
remove(i);
for(j=R[i];j!=i;j=R[j]){
if(nc[j]!=-1)remove(j);
}
if(dfs(d+1,lim))key = 1;
for(j=L[i];j!=i;j=L[j]){
if(nc[j]!=-1)resume(j);
}
resume(i);
if(key)break;
}
if(key)return true;
return false;
}
int solve(int n){
int l = 0,r = n,m,ans;
while(l <= r){
m = (l+r) >> 1;
if(dfs(0,m)){
ans = m;
r = m - 1;
}
else {
l = m + 1;
}
}
return ans;
}
map<string,int> name;
string s;
void init_name(int n){
name.clear();
for(int i=0;i<n;i++){
cin >> s;
name[s] = i;
}
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
init_name(n);
init();
for(int i=0;i<n;i++){
insert(i,i);
}
for(int i=0;i<m;i++){
cin >> s;
int id = name[s];
int t;
//insert(id,id);
scanf("%d",&t);
while(t --){
cin >> s;
int idd = name[s];
insert(id,idd);
}
}
int ans = solve(n);
printf("%d\n", ans);
}
return 0;
}