2017.10.16 T2 1984
样例数据
输入
1
1
2 0
2 1 2
3 3 3 3
4 4 4 4 4
5 5 5 5 5 5
输出
3
分析:如果这道题硬跑dfs,emmmm,
420
次绝对炸(当然前50%还是能拿的)。考试的时候想正反两个dfs(一个是原图走10次,一个是读入的图走10次),将正dfs放到hash表中,看反dfs能否在10次内找到hash值,如果能就可以输出dep1+dep2,但是没能调出来orz(hash表果然玄学)。
⇐
其实这是一个正解,气
另一种方法也很玄学,那就是A*剪枝(一种提前判断并排除不优路径的方法,写出来的程序快慢与否取决于选手剪枝判断函数够不够优秀),但是对于这道题的数据,跑的那个快啊……
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;
int getint()
{
int sum=0,f=1;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar())
sum=(sum<<3)+(sum<<1)+ch-48;
return sum*f;
}
const int org[7][7]={0,0,0,0,0,0,0,//直接预处理原图
0,0,0,0,0,0,0,
0,1,1,0,0,0,0,
0,2,2,2,0,0,0,
0,3,3,3,3,0,0,
0,4,4,4,4,4,0,
0,5,5,5,5,5,5};
const int fx[5]={0,-1,1,-1,1};
const int fy[5]={0,-1,0,0,1};
int T,bjx,bjy,ans;
int a[7][7];
bool bjans;
int Ax()//判断函数:比对原图和现在的图,看还有多少个不同,也就是至少还需要走多少步
{
int res=-1;//因为两个位置不同最少一步(它俩互换),同理n个位置不同最少n-1步,所以刚开始res=-1
for(int i=1;i<=6;++i)
for(int j=1;j<=i;++j)
if(a[i][j]!=org[i][j])
res++;
return res;
}
void dfs(int dep,int x,int y)
{
if(Ax()==-1)//A*剪枝1:已经全部配好,更新答案,回退
{
ans=min(ans,dep);
bjans=1;
return;
}
if(Ax()+dep>ans)//A*剪枝2:至少需要走的和已经走的加起来超过ans,便不是最优值了,回退
return;
if(x>ans-dep)//A*剪枝3:0所在的层数比还能走的步数还大,也就是0现在根本无法返回到第一层,回退
return;
for(int i=1;i<=4;++i)//正常的dfs
{
int newx=x+fx[i];
int newy=y+fy[i];
if(newx>=1&&newx<=6&&newy>=1&&newy<=newx)
{
swap(a[x][y],a[newx][newy]);
dfs(dep+1,newx,newy);
swap(a[x][y],a[newx][newy]);
}
}
}
int main()
{
freopen("blocks.in","r",stdin);
freopen("blocks.out","w",stdout);
T=getint();
while(T--)
{
for(int i=1;i<=6;++i)
for(int j=1;j<=i;++j)
{
a[i][j]=getint();
if(a[i][j]==0)
bjx=i,bjy=j;
}
ans=20,bjans=0;//赋初值
dfs(0,bjx,bjy);
if(bjans)
cout<<ans<<'\n';
else
cout<<"too difficult"<<'\n';
}
return 0;
}
本题结。