题意:以街头霸王为背景的一个题。有N个人物,每个人物有一到两种模式,每种模式有他特定可以击败的一些特定模式的人物。
现在要选择一些人物,同时要确定他们的模式,使得这些人能够击败剩下其他人的所有模式。
求要选择的最少的人物数。一个人物只能选择一种模式。
还是采用DLX搜索来解。
因为人物最多25个,总的模式最多50。
可以将人物的模式重新编号。然后根据输入连接。这里要注意两点:
1、已选择的人物不用击败,反过来说明选择一个人物,他自己的所有模式就都击败了;
2、同一人物只能选择一种模式,所以要注意记录好那个人物被选了。
然后就还是个经典的重复覆盖问题了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 100;
const int M = 3000;
typedef pair<int,int> pii;
vector<pii> V[N];
int T, n, m, sz, ans;
int a[N], beat[N][2][10], mode[N][2][10], id[N][2];
int L[M], R[M], U[M], D[M], col[M], cha[M], row[N], S[N];
void init(){
for(int i=0; i<=m; i++){
L[i] = i-1;
R[i] = i+1;
U[i] = D[i] = i;
S[i] = 0;
row[i] = -1;
}
L[0] = m;
R[m] = 0;
sz = m+1;
}
void link(int ch, int r, int c){
S[c]++;
col[sz] = c;
cha[sz] = ch;
U[sz] = U[c];
D[sz] = c;
U[D[sz]] = D[U[sz]] = sz;
if(~row[r]){
R[sz] = R[row[r]];
L[sz] = row[r];
L[R[sz]] = R[L[sz]] = sz;
}
else{
L[sz] = R[sz] = sz;
}
row[r] = sz;
sz++;
}
bool use[N];
void remove(int x){
for(int i=D[x]; i!=x; i=D[i]){
L[R[i]] = L[i];
R[L[i]] = R[i];
}
}
void restore(int x){
for(int i=U[x]; i!=x; i=U[i]){
L[R[i]] = R[L[i]] = i;
}
}
bool vis[N];
bool h(int res){
if(res>=ans) return 0;
memset(vis, 0, sizeof(vis));
for(int i=R[0]; i!=0; i=R[i]){
if(!vis[i]){
res++;
if(res>=ans) return 0;
vis[i] = 1;
for(int j=D[i]; j!=i; j=D[j]){
for(int k=R[j]; k!=j; k=R[k]){
vis[col[k]] = 1;
}
}
}
}
return 1;
}
void dfs(int dep){
if(!h(dep)) return;
if(!R[0]){
ans = dep;
return;
}
int c = R[0];
for(int i=R[c]; i; i=R[i]){
if(S[i]<S[c]) c=i;
}
for(int i=D[c]; i!=c; i=D[i]){
if(use[cha[i]]) continue;
use[cha[i]] = 1;
remove(i);
for(int j=L[i]; j!=i; j=L[j]) remove(j);
dfs(dep+1);
for(int j=R[i]; j!=i; j=R[j]) restore(j);
restore(i);
use[cha[i]] = 0;
}
}
int solve(){
init();
ans = n;
for(int i=1; i<=n; i++){
for(int j=0; j<a[i]; j++){
int x = id[i][j];
for(int k=0; k<V[x].size(); k++){
pii &p = V[x][k];
link(i, x, id[p.first][p.second]);
}
}
}
memset(use, 0, sizeof(use));
dfs(0);
return ans;
}
int main(){
scanf("%d", &T);
for(int t=1; t<=T; t++){
scanf("%d", &n);
m = 0;
int b, c, d;
for(int i=1; i<=n; i++){
scanf("%d", a+i);
for(int j=0; j<a[i]; j++){
id[i][j] = ++m;
V[m].clear();
scanf("%d", &b);
for(int k=0; k<b; k++){
scanf("%d %d", &c, &d);
V[m].push_back(make_pair(++c,d));
}
for(int k=0; k<a[i]; k++){
V[m].push_back(make_pair(i, k));
}
sort(V[m].begin(), V[m].end());
}
}
printf("Case %d: %d\n", t, solve());
}
return 0;
}