FZU1686 神龙的难题 dancing links 重复覆盖
分析:每次可以打一个小矩阵的怪,然后把每个怪看成一列,然后每个小矩阵看成一行,枚举左上角就行
注:然后注意总共的节点数是新图的行*列的个数,不是原图
#include<cstdio> #include<cstring> #include<queue> #include<cstdlib> #include<algorithm> #include<vector> #include<cmath> using namespace std; typedef long long LL; const int N=230*230; const double eps=1e-8; int n,m,sz,k; int u[N],l[N],r[N],d[N]; int h[230],s[230],col[N]; void init() { for(int i=0; i<=m; ++i) { s[i]=0; u[i]=d[i]=i; l[i]=i-1; r[i]=i+1; } r[m]=0; l[0]=m; sz=m; for(int i=1; i<=n; ++i) h[i]=-1; } void link(int x,int y) { ++sz; ++s[y],col[sz]=y; u[sz]=u[y],d[u[y]]=sz; d[sz]=y,u[y]=sz; if(h[x]==-1)h[x]=l[sz]=r[sz]=sz; { l[sz]=l[h[x]]; r[l[h[x]]]=sz; r[sz]=h[x]; l[h[x]]=sz; } } void del(int y) { for(int i=d[y]; i!=y; i=d[i]) r[l[i]]=r[i],l[r[i]]=l[i]; } void resume(int y) { for(int i=d[y]; i!=y; i=d[i]) r[l[i]]=l[r[i]]=i; } bool vis[230]; int f() { int ret=0; for(int i=r[0]; i; i=r[i]) vis[i]=0; for(int i=r[0]; i; i=r[i]) { if(vis[i])continue; vis[i]=1; ++ret; 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 ret; } int ans; void dance(int pos) { if(pos+f()>=ans)return; if(!r[0]) { ans=min(pos,ans); return; } int t=r[0]; for(int i=r[0]; i!=0; i=r[i]) if(s[i]<s[t])t=i; for(int i=d[t]; i!=t; i=d[i]) { del(i); for(int j=r[i]; j!=i; j=r[j]) del(j); dance(pos+1); for(int j=l[i]; j!=i; j=l[j]) resume(j); resume(i); } } int mp[20][20]; int main() { int n1,m1; while(~scanf("%d%d",&n,&m)) { int cnt=0,tot=0; for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) { scanf("%d",&mp[i][j]); if(mp[i][j]==1)mp[i][j]=++cnt; } scanf("%d%d",&n1,&m1); int tmp=(n-n1+1)*(m-m1+1); swap(n,tmp),swap(m,cnt); init(); swap(n,tmp),swap(m,cnt); for(int i=1;n-i+1>=n1;++i) { for(int j=1;m-j+1>=m1;++j) { ++tot; for(int x=i;x<i+n1;++x) for(int y=j;y<j+m1;++y) if(mp[x][y]!=0)link(tot,mp[x][y]); } } ans=230; dance(0); printf("%d\n",ans); } return 0; }