卧薪尝胆,厚积薄发。
Street Fighter
Date: Fri Aug 10 22:26:36 CST 2018 In Category: NoCategory

Description:

有 $N$ 个人物,每个人物有一到两种模式,每种模式有他特定可以击败的一些特定模式的人物。
现在要选择一些人物,同时要确定他们的模式,使得这些人能够击败剩下其他人的所有模式。
求要选择的最少的人物数。一个人物只能选择一种模式。 $T\le 30$ $N \le 25$

Solution:

重复覆盖问题,可以用 $dancinglinks+Astar$ 求解,建模不是很难,一个人物只能选择一种模式,就记一下当前这个人是不是选过,动态开列。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
inline int read()
{
register int res = 0;
register char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res;
}
int n;
#define MAXN 50 * 50 * 2
struct dlx
{
int L[MAXN],R[MAXN],U[MAXN],D[MAXN],row[MAXN],col[MAXN],s[MAXN],h[MAXN],head,cnt;
int n,m;
int ans;
bool used[MAXN];
void init(int _n,int _m)
{
memset(s,0,sizeof(s));
memset(h,-1,sizeof(h));
memset(U,0,sizeof(U));
memset(D,0,sizeof(D));
memset(L,0,sizeof(L));
memset(R,0,sizeof(R));
memset(row,0,sizeof(row));
memset(col,0,sizeof(col));
memset(used,0,sizeof(used));
n = _n;m = _m;
head = 0;L[0] = R[0] = 0;
cnt = m;
s[0] = INF;
ans = INF;
return;
}
void addcol(int c)
{
L[c] = L[head];R[c] = head;R[L[c]] = c;L[R[c]] = c;
D[c] = c;U[c] = c;
return;
}
void add(int r,int c)
{
if(D[c] == 0)addcol(c);
++cnt;
++s[c];
row[cnt] = r;col[cnt] = c;
U[cnt] = c;D[cnt] = D[c];U[D[cnt]] = cnt;D[U[cnt]] = cnt;
if(h[r] == -1)h[r] = L[cnt] = R[cnt] = cnt;
else
{
L[cnt] = L[h[r]];R[cnt] = h[r];R[L[cnt]] = cnt;L[R[cnt]] = cnt;
}
return;
}
void remove(int k)
{
for(int i = D[k];i != k;i = D[i])
R[L[i]] = R[i],L[R[i]] = L[i];
return;
}
void resume(int k)
{
for(int i = U[k];i != k;i = U[i])
R[L[i]] = i,L[R[i]] = i;
return;
}
bool v[MAXN];
int g()
{
int cost = 0;
for(int i = R[head];i != 0;i = R[i])v[i] = false;
for(int i = R[head];i != 0;i = R[i])
if(!v[i])
{
++cost;
v[i] = true;
for(int j = D[i];j != i;j = D[j])
for(int k = R[j];k != j;k = R[k])
v[col[k]] = true;
}
return cost;
}
void dance(int dep)
{
if(dep + g() >= ans)return;
if(R[head] == head)
{
ans = dep;return;
}
int mcol = 0;
for(int i = R[0];i != mcol;i = R[i])
if(s[i] < s[mcol])
mcol = i;
for(int i = D[mcol];i != mcol;i = D[i])
{
if(used[(row[i] - 1) / 2 + 1])continue;
used[(row[i] - 1) / 2 + 1] = true;
remove(i);
for(int j = R[i];j != i;j = R[j])remove(j);
dance(dep + 1);
for(int j = R[i];j != i;j = R[j])resume(j);
resume(i);
used[(row[i] - 1) / 2 + 1] = false;
}
return;
}
}dlx;
void work(int t)
{
scanf("%d",&n);
dlx.init(2 * n,2 * n);
int m,k;
int a,b;
for(int i = 1;i <= n;++i)
{
scanf("%d",&m);
for(int j = 1;j <= m;++j)
{
scanf("%d",&k);
for(int l = 1;l <= k;++l)
{
scanf("%d%d",&a,&b);
++a;++b;
dlx.add((i - 1) * 2 + j,(a - 1) * 2 + b);
}
}
for(int j = 1;j <= m;++j)
for(int k = 1;k <= m;++k)
dlx.add((i - 1) * 2 + j,(i - 1) * 2 + k);
}
dlx.dance(0);
cout << "Case " << t << ": " << dlx.ans << endl;
return;
}
int main()
{
int T = read();
for(int i = 1;i <= T;++i)
work(i);
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡