DFS加减枝。
/**
需要加各种减枝,如当前到达的地方能否再走n-d步达到原点
*/
#include<iostream>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
struct dot
{
int x,y;
dot(int x=0,int y=0):x(x),y(y){}
bool operator == (const dot rhs) const{
return x == rhs.x && y == rhs.y;
}///定义==运算符,这样下面的find才能用
};
int n,k,cnt=0;
///n和k是输入的步数和障碍点的个数,cnt存放正确路径个数
const int dir[4][2] = { {1,0},{0,1},{0,-1},{-1,0} };
///方向数组,定义东,北,西,南,加的时候用横坐标+[i][0],纵坐标+[i][1]
const char dict[4] = { 'e','n','s','w'};
///这个要和上面对应
int note[1024];///这个才是输出序列,存放所有方向
dot block[64],vis[1024];
///block放障碍点,vis放经过的点,因为经过的停留点事不能重复的
///这个很关键
///到了牛逼的地方了
void DFS(int curdir, int d, int x, int y)
///d记录当前的步数,下一步该走d+1步
///x,y是当前坐标
///curdir存放的是现在人站的方向,或者说是上一次转弯的方向
{
if(d == n){///已经走完了d次的路
if(x || y) return;
///x和y不同时为0,并没有回到原点
for(int i=0;i<n;i++)
printf("%c", dict[note[i]]);
///按eswn输出一条正确路径
printf("\n");
++cnt;
return;
}
for(int i=0; i<4; i++)
{
if( (i == 0 || i == 3) && (curdir == 0 || curdir == 3) ) continue;
if( (i == 1 || i == 2) && (curdir == 1 || curdir == 2) ) continue;
///每次必须要转90度嘛,所以如果上次转的南北没这次就不能往南北转了
dot v(x,y);
///把当前的位置坐标赋值给v
if((n-d-1)*n < abs(v.x + (d+1)*dir[i][0]) + abs(v.y + (d+1)*dir[i][1]) )
///我认为这是很关键的算法,(n-d-1)*n把剩下的转弯次数与n相乘,就是后面能走的最大步数,当然达不到这个数
///abs(v.x + (d+1)*dir[i][0]) + abs(v.y + (d+1)*dir[i][1])这个就是从当前位置回到(0,0)的最小步数
///如果达不到的最大的 都要比实际走向目的地的步数小
///那这条路径走完剩下的d肯定回不到(0,0)的
goto loop; ///直接跳转到最后
///有可能走到的话,走d+1步
for(int j=0; j<d+1;++j){
v.x += dir[i][0];
v.y += dir[i][1];
///向一个方向走d+1步
if(find(block, block + k, v) != block + k)
///中途路过障碍点,取消该路径
goto loop; ///直接跳转到最后
}
if(find(vis, vis + d, v) == vis + d)
///走完d+1步后,该节点没有到过,这也是题目说的不能重复游览
{
vis[d] = v;///v记录到vis,用于上面的if
note[d] = i;///存入转弯方向序列
DFS(i,d+1,v.x,v.y);
///如果该点可行,继续向下搜,d+1,i记录本次转的方向
}
loop:;
///直接跳转到这的,这条路就被废了
}
}
void init()
{
cnt=0;
///把所有数组都清零
memset(vis, 0, sizeof(vis));
memset(block, 0, sizeof(block));
memset(note, 0, sizeof(note));
}
int main()
{
ios::sync_with_stdio(false);
///.关闭输入输出缓冲同步,实现cin和cout跟scanf和printf几乎相同的速度
int T;
cin >> T;
while(init(), T--)
{
cin>>n>>k;
for(int i=0;i<k;i++)
{
dot t;
cin>>t.x>>t.y;
block[i]=t;
}
DFS(-1,0,0,0);
///后两个00是初始坐标(0,0)
printf("Found %d golygon(s).\n\n", cnt);
}
return 0;
}