直接暴力搜索,一开始我用map保存的障碍点,但是超时了 。因此必须用数组来直接保存 ; 但是由于坐标点有负数,而且所走的最大距离不超过n*(n+1)/2 ,所以我们不妨将坐标原点移动一定的距离,这样所有的坐标就都是正数了,可以直接判断某个点是不是障碍 。 由于不能重复访问同一个地点,记录访问过的点 。 由于要按照字典序输出,我们搜索的时候按照enswd的顺序就行了 。
有一个可以用来剪枝的条件: 当前的横坐标的绝对值加纵坐标绝对值如果大于之后需要走的路程,那么肯定到达不了原点,直接return ;
细节参见代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 444;
int T,n,m,ans,x,y,vis[maxn][maxn],g[maxn][maxn];
char s[50];
void init() {
scanf("%d%d",&n,&m);
memset(vis,0,sizeof(vis));
memset(g,0,sizeof(g));
for(int i=0;i<m;i++) {
scanf("%d%d",&x,&y);
if(abs(x)>222||abs(y)>222) continue; //扩大坐标
g[x+222][y+222] = 1;
}
}
void dfs(int x,int y,int cur ,char c) {
if(cur > n) return ;
int v = ((n)*(n+1) - (cur)*(cur+1))/2;
if(v < abs(x-222)+abs(y-222)) return ; //剪枝
if(cur == n && x == 222 && y == 222) {
s[n] = '\0'; printf("%s\n",s); ++ans;
return ;
}
if(c == 'n' || c == 's') {
bool ok = true;
for(int i=x;i<=x+cur+1;i++) if(g[i][y]) { ok = false; break; }
if(ok&&!vis[x+cur+1][y]) { s[cur] = 'e'; vis[x+cur+1][y]=1; dfs(x+cur+1,y,cur+1,'e'); vis[x+cur+1][y] = 0; }
ok = true;
for(int i=x;i>=x-cur-1;i--) if(g[i][y]) { ok = false; break; }
if(ok&&!vis[x-cur-1][y]) { s[cur] = 'w'; vis[x-cur-1][y]=1; dfs(x-cur-1,y,cur+1,'w'); vis[x-cur-1][y]=0; }
}
if(c == 'w' || c == 'e') {
bool ok = true;
for(int i=y;i<=y+cur+1;i++) if(g[x][i]) { ok = false; break; }
if(ok&&!vis[x][y+cur+1]) { s[cur] = 'n'; vis[x][y+cur+1]=1; dfs(x,y+cur+1,cur+1,'n'); vis[x][y+cur+1]=0; }
ok = true;
for(int i=y;i>=y-cur-1;i--) if(g[x][i]) { ok = false; break; }
if(ok&&!vis[x][y-cur-1]) { s[cur] = 's'; vis[x][y-cur-1]=1; dfs(x,y-cur-1,cur+1,'s'); vis[x][y-cur-1]=0; }
}
return;
}
int main() {
scanf("%d",&T);
while(T--) {
init();
ans = 0;
s[0] = 'e'; dfs(223,222,1,'e');//第一步
s[0] = 'n'; dfs(222,223,1,'n');
s[0] = 's'; dfs(222,221,1,'s');
s[0] = 'w'; dfs(221,222,1,'w');
printf("Found %d golygon(s).\n\n",ans);
}
return 0;
}