UCF Local Programming Contest 2015 H. Reach for the Stars
https://nanti.jisuanke.com/t/43393
搜索:以印章的最上面位置为搜索点
剪枝1:搜索空间去掉第一列、最后一列、最后两行。因为这些位置不能作为印章的最上方
剪枝2:最优性剪枝
剪枝3:当此处不作为印章最上面位置时,有些地方永远也覆盖不了了。
比赛时T飞的原因:
1、判断可行性时对整个棋局判断,其实每次只会涉及5个位置,判断这5个位置即可
2、剪枝不到位。剪枝3没想到
#include<cstring> #include<cstdio> using namespace std; int n,m,tot,ans; char s[10][10]; int a[82][2]; void dfs(int now,int step,int left) { if(step+(tot-now+1)/5>=ans) return; if(!left) { ans=step; return; } if(now==tot+1) return; char tmp[5]; int x,y,cnt; bool no; for(int i=now;i<=tot;++i) { x=a[i][0]; y=a[i][1]; no=false; cnt=0; tmp[0]=s[x][y]; tmp[1]=s[x+1][y-1]; tmp[2]=s[x+1][y]; tmp[3]=s[x+1][y+1]; tmp[4]=s[x+2][y]; for(int j=0;j<5 && !no;++j) if(tmp[j]=='.') no=true; else if(tmp[j]=='#') cnt++; if(!no) { s[x][y]=s[x+1][y-1]=s[x+1][y]=s[x+1][y+1]=s[x+2][y]='@'; dfs(i+1,step+1,left-cnt); s[x][y]=tmp[0]; s[x+1][y-1]=tmp[1]; s[x+1][y]=tmp[2]; s[x+1][y+1]=tmp[3]; s[x+2][y]=tmp[4]; } if(s[x][y]=='#') return; if(y==2 && s[x+1][1]=='#') return; if(y==m-1 && s[x+1][m]=='#') return; if(x==n-2 && s[n][y]=='#') return; } } int main() { int T,sum; scanf("%d",&T); for(int tt=1;tt<=T;++tt) { scanf("%d%d",&n,&m); tot=sum=0; for(int i=1;i<=n;++i) { scanf("%s",s[i]+1); for(int j=1;j<=m;++j) if(s[i][j]=='#') { sum++; if(i<=n-2 && j>=2 && j<=m-1) a[++tot][0]=i,a[tot][1]=j; } } ans=100; dfs(1,0,sum); printf("Image #%d: ",tt); if(ans==100) printf("impossible\n"); else printf("%d\n",ans); if(tt<T) printf("\n"); } return 0; }