[SCOI2005]骑士精神

题面传送门

我们发现只有25个格子,应该是可以用爆搜过掉这道题的。但是裸的dfs时间复杂度过高,我们要进行相应的优化。

首先,由于马的数量过多,我们应该选择让空格“走”。

接下来我们发现这道题又很明显的一个限制条件,最多不能超过15步,所以我们可以使用迭代加深进行优化,所谓的迭代加深搜索,本质上还是dfs,但是它每次会设置一个深度上限maxdep,使得搜索树的深度不超过maxdep,这样做可以让它遍历更多的分支,更广泛的求解。

然而,即使加上了迭代加深优化,我们依然不能通过此题,因此我们引入了第二种优化:启发式搜索,著名的A*算法就是一种启发式搜索。

来自https://blog.csdn.net/denghecsdn/article/details/78778769的A*核心思想详解:

“A*成功的秘决在于,它把Dijkstra算法(靠近初始点的结点)和BFS算法(靠近目标点的结点)的信息块结合起来。在讨论A*的标准术语中,g(n)表示从初始结点到任意结点n的代价,h(n)表示从结点n到目标点的启发式评估代价(heuristic estimated cost)。在上图中,yellow(h)表示远离目标的结点而teal(g)表示远离初始点的结点。当从初始点向目标点移动时,A*权衡这两者。每次进行主循环时,它检查f(n)最小的结点n,其中f(n) = g(n) + h(n)。”

然而上述思想显然是针对BFS的,我们可以结合迭代加深将其“改造”成我们需要的dfs算法,这种算法就叫做启发式迭代加深搜索(IDA*)

那么回到这个题目本身,我们如何设计这个估价函数呢?我们发现,在最乐观的情况下,每次交换时,都把相应棋子交换到标准位置,因此我们只要统计最终状态和当前状态不一样的数量即可。

然后使用IDA*搜索即可。

参考代码:

 1 #pragma GCC optimize(3,"Ofast","inline") 
 2 #include
 3 #include
 4 #include
 5 #define int long long
 6 using namespace std;
 7 int read()
 8 {
 9     int x=0,f=1;char ch=getchar();
10     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
11     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
12     return x*f;
13 }
14 int n;
15 int _std[10][10]=
16 {
17     {0,0,0,0,0,0},
18     {0,1,1,1,1,1},
19     {0,0,1,1,1,1},
20     {0,0,0,2,1,1},
21     {0,0,0,0,0,1},
22     {0,0,0,0,0,0}
23 };
24 int dx[8]={-1,1,2,2,1,-1,-2,-2};
25 int dy[8]={-2,-2,-1,1,2,2,1,-1};
26 int a[10][10],T,suc,sx,sy;
27 char ch;
28 int evaluate()
29 {
30     int cnt=0;
31     for(int i=1;i<=5;i++)
32     {
33         for(int j=1;j<=5;j++)
34         {
35             if(a[i][j]!=_std[i][j])++cnt;
36         }
37     }
38     return cnt;
39 }
40 void A_star(int step,int x,int y,int maxdep)
41 {
42     if(step==maxdep)
43     {
44         if(!evaluate())suc=step;
45         return;
46     }
47     for(int i=0;i<=7;i++)
48     {
49         int xx=x+dx[i],yy=y+dy[i];
50         if(xx<1||xx>5||yy<1||yy>5)continue;
51         swap(a[xx][yy],a[x][y]);
52         if(step+evaluate()<=maxdep)A_star(step+1,xx,yy,maxdep);
53         swap(a[xx][yy],a[x][y]);
54     }
55 }
56 signed main()
57 {
58     freopen("knight.in","r",stdin);
59     freopen("knight.out","w",stdout);
60     ios::sync_with_stdio(0);
61     cin>>T;
62     while(T--)
63     {
64         suc=0;
65         for(int i=1;i<=5;i++)
66         {
67             for(int j=1;j<=5;j++)
68             {
69                 cin>>ch;
70                 if(ch=='*')a[i][j]=2,sx=i,sy=j;
71                 else a[i][j]=ch-'0';
72             }
73         }
74         if(!evaluate())
75         {
76             cout<<0<<"\n";
77             continue;
78         }
79         for(int i=1;i<=15;i++)
80         {
81             A_star(0,sx,sy,i);
82             if(suc)break;
83         }
84         if(suc)cout<endl;
85         else cout<<-1<<endl;
86     }
87     return 0;
88 }
[SCOI2005]骑士精神

 

  

你可能感兴趣的:([SCOI2005]骑士精神)