题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3529
题意:炸弹人游戏中,问最少需要放多少颗炸弹,才能够将所有的墙壁炸掉,其中,炸弹在同一时间引爆。
以墙壁这列,以空地为行,可转化为重复覆盖问题。
Code:
#include<stdio.h> #include<string.h> #include<stdlib.h> #define M 32 #define N 256 const int V=M*N; int U[V],D[V],C[V],R[V],L[V]; int S[M],H[N]; char s[M][M]; int cc[M][M]; int size,ak; int dir[][2]={{0,1},{0,-1},{1,0},{-1,0}}; bool hash[M]; void Remove(int c) { int i; for(i=D[c];i!=c;i=D[i]) L[R[i]]=L[i],R[L[i]]=R[i]; } void Resume(int c) { int i; for(i=U[c];i!=c;i=U[i]) L[R[i]]=R[L[i]]=i; } int h() { int r=0,i,j,k; memset(hash,false,sizeof(hash)); for(i=R[0];i;i=R[i]){ if(!hash[i]){ r++; for(j=D[i];j!=i;j=D[j]){ for(k=R[j];k!=j;k=R[k]) hash[C[k]]=true; } } } return r; } void Dance(int k) { int min,c,i,j; if(k+h()>=ak) return;//用大于号就超时了~ if(!R[0]){ if(k<ak) ak=k; return ; } for(min=V,i=R[0];i;i=R[i]){ if(S[i]<min) min=S[i],c=i; } for(i=D[c];i!=c;i=D[i]){ Remove(i); for(j=R[i];j!=i;j=R[j]) Remove(j); Dance(k+1); for(j=L[i];j!=i;j=L[j]) Resume(j); Resume(i); } } void Link(int r,int c) { S[c]++;C[size]=c; U[size]=U[c];D[U[c]]=size; D[size]=c;U[c]=size; if(H[r]==-1) L[size]=R[size]=H[r]=size; else{ L[size]=L[H[r]];R[L[H[r]]]=size; R[size]=H[r];L[H[r]]=size; }size++; } int main() { int n,m,c; int i,j,r,d; int x,y; while(~scanf("%d%d",&n,&m)){ for(i=0;i<n;i++) scanf("%s",s[i]); memset(cc,0,sizeof(cc)); for(c=0,i=0;i<n;i++){ for(j=0;j<m;j++){ if(s[i][j]=='#') cc[i][j]=++c; } } for(i=0;i<=c;i++){ S[i]=0;U[i]=D[i]=i; L[i+1]=i;R[i]=i+1; }R[c]=0;size=c+1; memset(H,-1,sizeof(H)); for(i=0,r=0;i<n;i++){ for(j=0;j<m;j++){ if(s[i][j]=='.'){ for(d=0;d<4;d++){ for(x=i,y=j;s[x][y]=='.'&&x>=0&&x<n&&y>=0&&y<m;x+=dir[d][0],y+=dir[d][1]); if(x>=0&&x<n&&y>=0&&y<m&&s[x][y]=='#') Link(r,cc[x][y]); }r++; } } }ak=V; Dance(0); printf("%d\n",ak); } return 0; }