这道题要使用DFS加上优化才可以过。
朴素的搜索只能解决到N=5,6会超时。于是要加上一些优化。
优化1
不走死胡同!所谓死胡同,就是走进去以后就再也无法走出来的点。
一种简单的想法是:"任意时刻,必须保证和当前所在位置不相邻的未经点至少有两个相邻的未经点"。基于这种想法,可以采取这样的优化:
该优化的力度很大,可以在0.2秒内解决N=6,但N=7仍然需要2秒左右的时间。
优化2
不要形成孤立的区域!如果行走过程中把路一分为二,那么肯定有一部分再也走不到了,需要剪枝。
形成孤立的区域的情况很多,如果使用Floodfill找连通快,代价会很大,反而会更慢。我只考虑了一种最容易出现特殊情况,即:
这样就会形成孤立的区域,只要将出现这种情况的状态都剪掉即可。
加上优化2,N=7也能在0.3s解决了。
Compiling...
Compile: OK
Executing...
Test 1: TEST OK [0.000 secs, 2844 KB]
Test 2: TEST OK [0.000 secs, 2840 KB]
Test 3: TEST OK [0.000 secs, 2844 KB]
Test 4: TEST OK [0.000 secs, 2840 KB]
Test 5: TEST OK [0.000 secs, 2840 KB]
Test 6: TEST OK [0.011 secs, 2840 KB]
Test 7: TEST OK [0.302 secs, 2840 KB]
All tests OK.
Your program ('betsy') produced all correct answers! This is your submission #5 for this problem. Congratulations!
/*
ID: cmykrgb1
PROG: betsy
LANG: C++
*/
#include <iostream>
#include <fstream>
#define MAX 9
using namespace std;
ifstream fi("betsy.in");
ofstream fo("betsy.out");
int N,N_2,cnt;
bool map[MAX][MAX];
int pi[4]={0,0,1,-1},pj[4]={1,-1,0,0};
void init()
{
int i,j,k;
fi >> N;
N_2=N*N;
for (i=0;i<=N+1;i++)
{
map[0][i]=map[N+1][i]=map[i][0]=map[i][N+1]=true;
}
map[1][1]=1;
}
void print()
{
fo << cnt << endl;
fi.close();
fo.close();
}
inline int getfree(int i,int j)
{
int v=0;
for (int k=0;k<4;k++)
{
if (!map[ i+pi[k] ][ j+pj[k] ])
v++;
}
return v;
}
void go(int i,int j,int step)
{
if (i==N && j==1)
{
if (step==N_2)
cnt++;
return;
}
if (
(map[i][j-1] && map[i][j+1] && !map[i-1][j] && !map[i+1][j])
||
(!map[i][j-1] && !map[i][j+1] && map[i-1][j] && map[i+1][j])
)
return;
int k,di,dj,f,cntf=0,ki,kj;
for (k=0;k<4;k++)
{
di=i+pi[k],dj=j+pj[k];
if (map[di][dj] || (di==N && dj==1)) continue;
f=getfree(di,dj);
if (f<2)
{
cntf++;
ki=di;
kj=dj;
}
}
if (cntf>1)
return;
else
{
if (cntf==1)
{
map[ki][kj]=true;
go(ki,kj,step+1);
map[ki][kj]=false;
}
else
{
for (k=0;k<4;k++)
{
di=i+pi[k],dj=j+pj[k];
if (!map[di][dj])
{
map[di][dj]=true;
go(di,dj,step+1);
map[di][dj]=false;
}
}
}
}
}
int main()
{
init();
go(1,1,1);
print();
return 0;
}
上次修改时间 2017-02-03