题目有图,不附了
这个题的步数最大才5步,目测直接暴力搜即可,除了各种细节恶心人之外,其实不是很难,虽然我打了半天…
bfs。
关于剪枝:
1:可行性剪枝。若当前某种颜色的方块只有1或2个,则剪掉。
2:最优性剪枝。如果某三行中某个颜色的方块[x1,y1]只会出现一次,则cnt++,跳一行继续搜。设给定的步数为n,若cnt+step>n则剪枝。
然而我的最优性剪枝并没有什么效果…时间总共大概3000+ms
当然我觉得没有必要交换两个颜色相同的方块
看SHY的题解,她的最优性剪枝是这样:
若某一行中存在某一种颜色,它只有1个或2个方块,则他必须借助其它行来帮助消除,设离当前行最近且含有当前颜色的行与当前行的距离是K,求出对于所有方块最大的maxk,则maxk就是消除全部方块的下界,如果step+maxk>n大,则剪枝。
不过测试了一下,把我的最优性剪枝换成SHY的,时间变成4600+ms…………
这里是代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
struct sta{
int map[7][8];
int x[7],y[7],g[7],step;
int hash;
sta()
{
memset(map,0,sizeof(map));
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(g,0,sizeof(g));
step=0;
hash=0;
}
}f;
int step;
bool checkend(const sta &a)
{
for(int i=1;i<=5;i++)
{
for(int j=1;j<=7;j++)
{
if(a.map[i][j]) return false;
}
}
return true;
}
bool hash[10000010];
void gethash(sta &a)
{
int mod=10000007;
int ans=0;
for(int i=1;i<=5;i++)
{
for(int j=1;j<=7;j++)
{
ans=( (ans%mod*10)%mod + a.map[i][j]%mod )%mod;
}
}
a.hash=ans;
}
void fall(sta &a)
{
for(int i=1;i<=5;i++)
{
int tot=1;
for(int j=1;j<=7;j++)
{
if(a.map[i][j])
{
a.map[i][tot]=a.map[i][j];
tot++;
}
}
for(int j=tot;j<=7;j++) a.map[i][j]=0;
}
}
const int dx[]={0,-1,1,0,0};
const int dy[]={0,0,0,1,-1};
int r[20][20],c[20][20];
bool change(sta &a)
{
memset(r,0,sizeof(r));
memset(c,0,sizeof(c));
for(int i=1;i<=5;i++)
{
for(int j=1;j<=7;j++)
if(a.map[i][j])
{
if(a.map[i][j]==a.map[i][j+1]&&a.map[i][j]==a.map[i][j+2])
{
r[i][j]=r[i][j+1]=r[i][j+2]=a.map[i][j];
}
if(a.map[i+1][j]==a.map[i][j]&&a.map[i][j]==a.map[i+2][j])
{
c[i][j]=c[i+1][j]=c[i+2][j]=a.map[i][j];
}
}
}
bool flag=0;
for(int i=1;i<=5;i++)
{
for(int j=1;j<=7;j++)
{
if(r[i][j]||c[i][j]) {a.map[i][j]=0;flag=1;}
}
}
return flag;
}
int t[20];
bool check(const sta &a)
{
memset(t,0,sizeof(t));
for(int i=1;i<=5;i++)
{
for(int j=1;j<=7;j++)
{
if(a.map[i][j])
{
t[a.map[i][j]]++;
}
}
}
bool flag=1;
for(int i=1;i<=10;i++)
{
if(t[i]) flag=0;
if(t[i]>=3) return true;
}
if(flag) return true;
return false;
}
bool vis[12][12];
bool checkhaha(const sta &a,int x,int y)
{
for(int i=x-1;i<=x+1;i++)
{
for(int j=1;j<=7;j++)
{
if(i==x&&j==y) continue;
if(a.map[x][y]==a.map[i][j]) return false;
}
}
return true;
}
int h(const sta &a)
{
memset(vis,0,sizeof(vis));
int ans=0;
for(int i=1;i<=5;i++)
{
for(int j=1;j<=7;j++)
{
if(a.map[i][j]&&!vis[i-1][j]&&checkhaha(a,i,j)) {vis[i][j]=1,ans++;i++;}
}
}
return ans;
}
queue<sta> q;
void bfs()
{
f.step=0;
gethash(f);
q.push(f);
while(q.size())
{
f=q.front(); q.pop();
if(checkend(f))
{
for(int i=1;i<=f.step;i++)
{
printf("%d %d %d\n",f.x[i]-1,f.y[i]-1,f.g[i]);
}
return ;
}
if(f.step==step) continue;
for(int i=1;i<=5;i++)
{
for(int j=1;j<=7;j++)
{
if(f.map[i][j])
{
if(i+1<=5&&f.map[i][j]!=f.map[i+1][j])
{
sta nxt=f;
swap(nxt.map[i][j],nxt.map[i+1][j]);
nxt.step++;
nxt.x[nxt.step]=i;
nxt.y[nxt.step]=j;
nxt.g[nxt.step]=1;
fall(nxt);
while(change(nxt)) fall(nxt);
gethash(nxt);
if(!hash[nxt.hash]&&check(nxt)&&h(nxt)+nxt.step<=step)
{
q.push(nxt);hash[nxt.hash]=1;
}
}
if(i-1>0&&f.map[i][j]!=f.map[i-1][j])
{
sta nxt=f;
swap(nxt.map[i][j],nxt.map[i-1][j]);
nxt.step++;
nxt.x[nxt.step]=i;
nxt.y[nxt.step]=j;
nxt.g[nxt.step]=-1;
fall(nxt);
while(change(nxt)) fall(nxt);
gethash(nxt);
if(!hash[nxt.hash]&&check(nxt))
{
q.push(nxt);hash[nxt.hash]=1;
}
}
}
}
}
}
puts("-1");
}
int main()
{
scanf("%d",&step);
for(int i=1;i<=5;i++)
{
int k,j=1;
while(~scanf("%d",&k)&&k) f.map[i][j]=k,j++;
}
bfs();
return 0;
}
删掉注释3500+B,原来有注释是5700B…我还改了好多次……