最小支配集问题,还有一个限制就是每个人只能选一次, 所以既是重复覆盖,又是精确覆盖,是Dancing Links的综合应用.
remove1为精确覆盖删除,remove2为重复覆盖删除, 一定要注意删除的顺序。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>
#include <map>
#include <string>
#include <climits>
#include <set>
#include <string>
#include <sstream>
#include <utility>
#include <ctime>
#include <bitset>
using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::stringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;
using std::unique;
using std::lower_bound;
using std::random_shuffle;
using std::bitset;
using std::upper_bound;
using std::multiset;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;
typedef LL TY;
typedef long double LF;
const int MAXN(110);
const int MAXM(110);
const int MAXE(10010);
const int MAXK(6);
const int HSIZE(31313);
const int SIGMA_SIZE(26);
const int MAXH(13);
const int INFI((INT_MAX-1) >> 1);
const ULL BASE(31);
const LL LIM(10000000);
const int INV(-10000);
const int MOD(20100403);
const double EPS(1e-7);
const LF PI(acos(-1.0));
template<typename T> void checkmax(T &a, T b){if(b > a) a = b;}
template<typename T> void checkmin(T &a, T b){if(b < a) a = b;}
template<typename T> T ABS(const T &a){return a < 0? -a: a;}
int M, ans;
struct DANCING_LINKS
{
int H[MAXN];
int S[MAXM];
int L[MAXE], U[MAXE], R[MAXE], D[MAXE], C[MAXE];
bool vis[MAXM];
int size;
void init(int n, int m)
{
for(int i = 0; i <= n; ++i) H[i] = -1;
for(int i = 0; i <= m; ++i)
{
S[i] = 0;
U[i] = D[i] = C[i] = i;
L[i+1] = i;
R[i] = i+1;
}
L[0] = m;
R[m] = 0;
size = m+1;
}
void link(int r, int c)
{
++S[C[size] = c];
D[size] = D[c];
U[D[c]] = size;
U[size] = c;
D[c] = size;
if(H[r] == -1) L[size] = R[size] = H[r] = size;
{
R[size] = R[H[r]];
L[R[H[r]]] = size;
L[size] = H[r];
R[H[r]] = size;
}
++size;
}
void remove1(int c)
{
L[R[c]] = L[c];
R[L[c]] = R[c];
for(int i = D[c]; i != c; i = D[i])
for(int j = R[i]; j != i; j = R[j])
{
--S[C[j]];
U[D[j]] = U[j];
D[U[j]] = D[j];
}
}
void resume1(int c)
{
L[R[c]] = R[L[c]] = c;
for(int i = U[c]; i != c; i = U[i])
for(int j = L[i]; j != i; j = L[j])
{
++S[C[j]];
U[D[j]] = D[U[j]] = j;
}
}
void remove2(int c)
{
for(int i = D[c]; i != c; i = D[i])
{
L[R[i]] = L[i];
R[L[i]] = R[i];
}
}
void resume2(int c)
{
for(int i = U[c]; i != c; i = U[i])
L[R[i]] = R[L[i]] = i;
}
int h()
{
int ret = 0;
for(int i = R[0]; i && i <= M; i = R[i]) vis[i] = false;
for(int i = R[0]; i && i <= M; i = R[i])
if(!vis[i])
{
++ret;
vis[i] = true;
for(int j = D[i]; j != i; j = D[j])
for(int k = R[j]; k != j; k = R[k])
vis[C[k]] = true;
}
return ret;
}
void dfs(int dep)
{
if(dep+h() >= ans) return;
int c, sz = INFI;
for(int i = R[0]; i && i <= M; i = R[i])
if(S[i] < sz)
{
c = i;
sz = S[i];
}
if(sz == INFI)
{
ans = dep;
return;
}
for(int i = D[c]; i != c; i = D[i])
{
for(int j = R[i]; j != i; j = R[j])
if(C[j] <= M) remove2(j);
remove2(i);
for(int j = R[i]; j != i; j = R[j])
if(C[j] > M) remove1(C[j]);
dfs(dep+1);
for(int j = L[i]; j != i; j = L[j])
if(C[j] > M) resume1(C[j]);
resume2(i);
for(int j = L[i]; j != i; j = L[j])
if(C[j] <= M) resume2(j);
}
}
} dlx;
int cnt[30];
int num[30][2];
vector<PAIR> beat[30][2];
int main()
{
int TC, n_case(0);
scanf("%d", &TC);
while(TC--)
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i)
{
beat[i][0].clear();
beat[i][1].clear();
}
M = 0;
for(int i = 0; i < n; ++i)
{
scanf("%d", cnt+i);
M += cnt[i];
for(int j = 0; j < cnt[i]; ++j)
{
int K, a, b;
scanf("%d", &K);
for(int k = 0; k < K; ++k)
{
scanf("%d%d", &a, &b);
beat[i][j].push_back(make_pair(a, b));
}
}
}
dlx.init(M, M+n);
int ind = 0;
for(int i = 0; i < n; ++i)
for(int j = 0; j < cnt[i]; ++j)
num[i][j] = ++ind;
for(int i = 0; i < n; ++i)
for(int j = 0; j < cnt[i]; ++j)
{
dlx.link(num[i][j], M+i+1);
for(int k = 0; k < cnt[i]; ++k)
dlx.link(num[i][j], num[i][k]);
for(int k = 0; k < beat[i][j].size(); ++k)
dlx.link(num[i][j], num[beat[i][j][k].first][beat[i][j][k].second]);
}
ans = INFI;
dlx.dfs(0);
printf("Case %d: %d\n", ++n_case, ans);
}
return 0;
}