建模很容易就能说清楚,但我一直想不出来。
要问为什么的话可能是因为这题要先预处理出来所有正方形,而我没做过要预处理的舞蹈链的题。所以想不到。
那就是预处理出来所有正方形,用一个long long来表示一个正方形,这个正方形有没有包含id这条边就用 (1<<id)&num判断。那怎么预处理所有正方形呢,枚举边长1-n的正方形,然后再枚举这个正方形左上方的顶点就能做出来。
然后就能建模了,火柴是行,所有按现有火柴能拼出来的正方形是列,与其说是精准覆盖倒也可以说是全部破坏。
http://exp-blog.com/2018/06/11/pid-113/
读到这篇文章,打算模板还是多写几遍吧。于是这个模板就是自己手写的,debug了一整个下午。最后发现我把 l[size] = l[h[r]]写成了l[size]=R[h[r]]。有点气。。
再说一下f()函数,加不加都ac了,耗时也差不多。但是有的题还是会卡这点常数。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<map> #include<iomanip> #include<algorithm> #include<vector> #define INF 2e9 #define maxnode 5000 using namespace std; int empty[70]; long long square[200];//这个正方形需要哪些火柴 struct DLX{ int n,m,size; int up[maxnode],down[maxnode],R[maxnode],l[maxnode]; int h[70],s[200],row[maxnode],col[maxnode]; int ansd; void init(int n1,int m1){ n=n1; m=m1; ansd=-1; for(int i=0;i<=m;i++){ up[i] = down[i] = i; l[i] = i-1; R[i] = i+1; s[i]=0; } size=m; l[0]=m; R[m]=0; for(int i=1;i<=n;i++) h[i]=-1; } void link(int r,int c){ row[ ++size ] = r; col[size]=c; s[c]++; up[size] = down[c]; down[size]=c; down[up[c]]=size; up[c]=size; if( h[r]==-1 ) l[size]=R[size]=h[r]=size; else{ l[size]=l[h[r]]; R[size]=h[r]; R[l[h[r]]]=size; l[h[r]]=size; } } void remove(int c){ for(int i=down[c];i!=c;i=down[i]){ R[l[i]] = R[i]; l[R[i]] = l[i]; } } void resume(int c){ for(int i=down[c];i!=c;i=down[i]){ R[l[i]]=i; l[R[i]]=i; } } bool vis[200]; int f(){ int ret=0; for(int i=R[0];i!=0;i=R[i]) vis[i]=true; for(int i=R[0];i!=0;i=R[i]){ if( vis[i] ){ ret++; vis[i]=false; for(int j=down[i];j!=i;j=down[j]){ for(int k=R[j];k!=j;k=R[k]) vis[ col[k] ]=false; } } } return ret; } void dance(int d){ if( ansd!=-1 && d>=ansd ) return; if( R[0]==0 ){ ansd=d; return; } int c=R[0]; for(int i=R[c];i!=0;i=R[i]){ if( s[i]<s[c] ) c=i; } for(int i=down[c];i!=c;i=down[i]){ remove(i); for(int j=R[i];j!=i;j=R[j]) remove(j); dance(d+1); for(int j=R[i];j!=i;j=R[j]) resume(j); resume(i); } } }dlx; int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ memset(empty,0,sizeof(empty)); int n,k1; cin>>n>>k1; for(int i=1;i<=k1;i++){ int id; cin>>id; empty[id]=1; } int cnt=0;//有这么多个正方形 for(int i=1;i<=n;i++){//搜索长度为i的正方形 for(int j=0;j<=n-i;j++){ for(int k=0;k<=n-i;k++){ //正方形的左上角在(j,k) //这样构造出来的正方形要哪些火柴 long long num=0; bool configure=true; //上边 int id=k*(n+n+1)+j; for(int j1=1;j1<=i;j1++){ id+=1; if( empty[id] ) configure=false; num+= (long long)1<<id; } //左边 id=k*(n+n+1)+j-n; for(int k1=1;k1<=i;k1++){ id+=(n+n+1); if( empty[id] ) configure=false; num+= (long long)1<<id; } //下边 id=(k+i)*(n+n+1)+j; for(int j1=1;j1<=i;j1++){ id++; if( empty[id] ) configure=false; num+= (long long)1<<id; } //右边 id=k*(n+n+1)+j+i-n; for(int k1=1;k1<=i;k1++){ id+=n+n+1; if( empty[id] ) configure=false; num+= (long long)1<<id; } if( configure ) square[++cnt]=num; } } } dlx.init(2*n*(n+1),cnt); for(int i=1;i<=2*n*(n+1);i++){ for(int j=1;j<=cnt;j++){ if( ((long long)1<<i)&square[j] ) dlx.link(i,j); } } dlx.dance(0); cout<<dlx.ansd<<endl; } return 0; }
原文地址:https://www.cnblogs.com/ZhenghangHu/p/9716624.html
时间: 2024-11-18 07:09:09