题意:
一个人从(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); } }