题意:
给N个怪,M个关系。
每个关系代表a和b是邻居。
然后问每次攻击你可以攻击一个怪以及它的全部邻居
问最少需要几次攻击能把怪全部杀死。
思路:
怪为行和列,然后对面每个怪的邻居都是这个怪的列建图。
也是比较裸的重复覆盖。
代码:
#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
#include"map"
#include"vector"
#define mod 1000000007
#define ll long long
using namespace std;
#define N 1010*100
#define RN 1010
#define CN 1010
struct DLX
{
int n,m,C;
int U[N],D[N],L[N],R[N],Row[N],Col[N];
int H[RN],S[CN],cnt,ans[RN];
void init(int _n,int _m)
{
n=_n;
m=_m;
for(int i=0; i<=m; i++)
{
S[i]=0;
U[i]=D[i]=i;
L[i]=(i==0?m:i-1);
R[i]=(i==m?0:i+1);
}
C=m;
for(int i=1; i<=n; i++) H[i]=-1;
}
void link(int x,int y)
{
C++;
Row[C]=x;
Col[C]=y;
S[y]++;
U[C]=U[y];
D[C]=y;
D[U[y]]=C;
U[y]=C;
if(H[x]==-1) H[x]=L[C]=R[C]=C;
else
{
L[C]=L[H[x]];
R[C]=H[x];
R[L[H[x]]]=C;
L[H[x]]=C;
}
}
void del(int x)
{
for(int i=D[x]; i!=x; i=D[i])
{
R[L[i]]=R[i];
L[R[i]]=L[i];
}
}
void rec(int x)
{
for(int i=U[x]; i!=x; i=U[i])
{
R[L[i]]=i;
L[R[i]]=i;
}
}
int used[CN];
int h()
{
int sum=0;
for(int i=R[0]; i!=0; i=R[i]) used[i]=0;
for(int i=R[0]; i!=0; i=R[i])
{
if(used[i]==0)
{
sum++;
used[i]=1;
for(int j=D[i]; j!=i; j=D[j]) for(int k=R[j]; k!=j; k=R[k]) used[Col[k]]=1;
}
}
return sum;
}
void dance(int x)
{
if(x+h()>=cnt) return ;
if(R[0]==0)
{
cnt=min(cnt,x);
return ;
}
int now=R[0];
for(int i=R[0]; i!=0; i=R[i])
{
if(S[i]<S[now])
now=i;
}
for(int i=D[now]; i!=now; i=D[i])
{
del(i);
for(int j=R[i]; j!=i; j=R[j]) del(j);
dance(x+1);
for(int j=L[i]; j!=i; j=L[j]) rec(j);
rec(i);
}
return ;
}
} dlx;
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=-1)
{
int mp[88][88];
memset(mp,0,sizeof(mp));
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
mp[a][b]=1;
mp[b][a]=1;
}
dlx.init(n,n);
for(int i=1;i<=n;i++)
{
dlx.link(i,i);
for(int j=1;j<=n;j++)
{
if(mp[i][j]==1) dlx.link(i,j);
}
}
dlx.cnt=999;
dlx.dance(0);
printf("%d\n",dlx.cnt);
}
return 0;
}