题意:
一个人从(0,0)开始,每次走的长度是1,2,3...,每次走完一段,就必须向左或向右转,停留的点不能重复,并且不能经过障碍物;
现在给出最后一步走多远,以及障碍物的位置,求最后又走回(0,0)点的方法有几种,输出每种走法,还有走法总数;
代码:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define mod 1000000007
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
//由于坐标可能出现负的,走到第20的时候总路程为210,所以设置limit为105
//给所有的坐标都加上limit,保证vis的可用性
const int maxn = 250 , inf = 0x3f3f3f3f , limit = 105 ;
//方向:0->西 1->北 2->南 3->西
//将他们按字典序排列,就可以按字典序输出
int dir[4][2]={{1,0},{0,1},{0,-1},{-1,0}};
char face[4] = {'e','n','s','w'};
int n,m,ans;
//step存路径,sum存总长度,vis为访问标记(-1为障碍物,0表示可以访问,1表示不能访问)
int step[50],sum[25],vis[maxn][maxn];
//剪枝
bool cant(int x,int y,int d,int f){
//按照f方向一步一步走,如果此时的位置超过了limit,之后肯定就回不来了
//或者出现障碍物
//剪枝
for(int i = 1 ; i <= d ;i ++ ){
x+=dir[f][0];
y+=dir[f][1];
if(abs(x)>limit||abs(y)>limit) return true;
if(vis[x+limit][y+limit]==-1) return true;
}
//剩余的步数走不到(0,0)剪枝
if(abs(x)+abs(y)>sum[n]-sum[d]) return true;
return false;
}
//第一个参数为x坐标,第二个为y坐标,第三个为需要走的距离,第四个为方向
void dfs(int x,int y,int d,int f){
//符合条件,输出
if(d>n){
if(x==0&&y==0){
for(int i = 1 ; i<= n; i++ ){
printf("%c",face[step[i]]);
}
printf("\n");
ans++;
}
return;
}
//向四个方向走
for(int i = 0 ; i < 4 ; i ++ ){
if(i==f||i+f==3) continue;//原来方向和反方向不能走
int xx = x + dir[i][0] * d;
int yy = y + dir[i][1] * d;
if(cant(x,y,d,i)) continue;
if(vis[xx+limit][yy+limit]) continue;
vis[xx+limit][yy+limit] = 1;//设置标记
step[d] = i ;
dfs(xx,yy,d+1,i);
vis[xx+limit][yy+limit] = 0;//清除标记
}
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;
//预处理到第i个城市的总路程
sum[0] = 0;
for(int i = 1 ; i <= 20 ; i++ )
sum[i] = i + sum[i-1];
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&m);
mem(vis);
ans = 0;
int a,b;
//障碍物设为-1
for(int i = 0 ; i < m ; i ++ ){
scanf("%d %d",&a,&b);
vis[a+limit][b+limit] = -1;
}
dfs(0,0,1,-1);
printf("Found %d golygon(s).\n\n",ans);
}
}