题目来源:http://poj.org/problem?id=1084
★这题做了一上午,一直在找bug,难受哇
题意:
现在有一个由边长为1的火柴拼成的正方形,火柴id 从上到下从左到右 。如果现在拿走一些火柴,问 最少 还需要拿走多少火柴,使得这个图形 不包含正方形
思路:
我们将 所有的火柴看做舞蹈链的行,所有的正方形看做舞蹈链的列 ~那问题就很简单了。
但是在舞蹈链初始化之前还是有点小麻烦的,比如怎么判断 该火柴是这个正方形的一部分
bool judge(dd a,dd b)
{
if(a.x1<b.x1||a.x2>b.x2||a.y1<b.y1||a.y2>b.y2) return 0;//外
if(a.x1>b.x1&&a.x1<b.x2&&a.y1>b.y1&&a.y1<b.y2) return 0;//内
if(a.x2>b.x1&&a.x2<b.x2&&a.y2>b.y1&&a.y2<b.y2) return 0;//内
return 1;
}
然后注意要check一下,不然整个dance会陷入死循环~
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
using namespace std;
const int N=1e4+5;
const int M=1e2+5;
const int mod=1e9+7;
const int inf=0x7fffffff;
const double eps=1e-8;
const int pi=acos(-1);
template<class T>
void read(T &x)
{
char c;x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
struct dd
{
int x1,x2,y1,y2;
dd(){};
dd(int xx1,int xx2,int yy1,int yy2):x1(xx1),x2(xx2),y1(yy1),y2(yy2){};
}edge[M],mat[M];
struct DLX
{
int n,m,cnt,ans;
int up[N],right[N],down[N],left[N],col[N];
int head[M],sz[M];
bool vis[M];
void init(int nn,int mm)
{
n=nn; m=mm; ans=inf;
for(int i=0;i<=m;i++){
up[i]=down[i]=i;
right[i]=i+1;
left[i]=i-1;
sz[i]=0;
}
right[m]=0; left[0]=m;
cnt=m;
for(int i=1;i<=n;i++) head[i]=-1;
}
void link(int r,int c)
{
++cnt;
col[cnt]=c;
sz[c]++;
up[cnt]=up[c];
down[cnt]=c;
down[up[c]]=cnt;
up[c]=cnt;
if(head[r]==-1) head[r]=right[cnt]=left[cnt]=cnt;
else{
int tmp=head[r];
right[cnt]=tmp;
left[cnt]=left[tmp];
right[left[tmp]]=cnt;
left[tmp]=cnt;
}
}
void check()
{
// cout<<m<<'x'<<endl;
for(int i=1;i<=m;i++){
if(!sz[i]){
// cout<<i<<endl;
right[left[i]]=right[i];
left[right[i]]=left[i];
}
}
}
void del(int c)
{
for(int i=down[c];i!=c;i=down[i]){
right[left[i]]=right[i];
left[right[i]]=left[i];
}
}
void res(int c)
{
for(int i=down[c];i!=c;i=down[i]){
right[left[i]]=left[right[i]]=i;
}
}
int f()
{
int sum=0;
for(int i=right[0];i!=0;i=right[i]) vis[i]=1;
for(int i=right[0];i!=0;i=right[i]){
if(vis[i]){
sum++;
vis[i]=0;
for(int j=down[i];j!=i;j=down[j]){
for(int l=right[j];l!=j;l=right[l]){
vis[col[l]]=0;
}
}
}
}
return sum;
}
void dance(int dep)
{
if(dep+f()>=ans) return ;
if(right[0]==0){ans=dep; return ;}
int now=right[0];
// cout<<now<<endl;
for(int i=now;i!=0;i=right[i]){
if(sz[i]<sz[now]) now=i;
}
for(int i=down[now];i!=now;i=down[i]){
del(i);
for(int j=right[i];j!=i;j=right[j]) del(j);
dance(dep+1);
for(int j=right[i];j!=i;j=right[j]) res(j);
res(i);
}
}
}dlx;
bool visedge[M],vismat[M];
bool judge(dd a,dd b)
{
if(a.x1<b.x1||a.x2>b.x2||a.y1<b.y1||a.y2>b.y2) return 0;//外
if(a.x1>b.x1&&a.x1<b.x2&&a.y1>b.y1&&a.y1<b.y2) return 0;//内
if(a.x2>b.x1&&a.x2<b.x2&&a.y2>b.y1&&a.y2<b.y2) return 0;
return 1;
}
int main()
{
int t; read(t);
while(t--){
int n; read(n);
int tot; read(tot);
int pn=0,pm=0;
for(int i=1;i<=n+1;i++){
for(int j=1;j<=n;j++) edge[++pn]=dd(i,i,j,j+1);
for(int j=1;j<=n+1;j++) if(i<=n) edge[++pn]=dd(i,i+1,j,j);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
if(i+k<=n+1&&j+k<=n+1) mat[++pm]=dd(i,i+k,j,j+k);
}
}
}
memset(visedge,0,sizeof visedge);
memset(vismat,0,sizeof vismat);
while(tot--){
int a; read(a);
visedge[a]=1;
for(int i=1;i<=pm;i++){
if(!vismat[i]){
if(judge(edge[a],mat[i]))
vismat[i]=1;
}
}
}
dlx.init(pn,pm);
int sum=0;
for(int i=1;i<=pn;i++) if(!visedge[i]){
for(int j=1;j<=pm;j++) if(!vismat[j]){
if(judge(edge[i],mat[j])){
dlx.link(i,j);
sum++;
}
}
}
dlx.check();
dlx.dance(0);
cout<<dlx.ans<<endl;
}
return 0;
}