POJ 1084 Square Destroyer【舞蹈鏈】【重復覆蓋】
阿新 • • 發佈:2018-09-28
函數 std sync height width inf als long end
建模很容易就能說清楚,但我一直想不出來。
要問為什麽的話可能是因為這題要先預處理出來所有正方形,而我沒做過要預處理的舞蹈鏈的題。所以想不到。
那就是預處理出來所有正方形,用一個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 namespacestd; 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; }
POJ 1084 Square Destroyer【舞蹈鏈】【重復覆蓋】