Uva225 Golygons 【dfs回溯】【习题7-2】

题目:Golygons

题意:平面上有k个障碍点。 从(0,0)点出发,第一次走1个单位,第二次走2个单位,……,第n次走n个单位,恰好回到(0,0)。 要求只能沿着东南西北方向走,且每次必须转弯90°(不能沿着同一个方向继续走,也不能后退)。 走出的图形可以自交,但不能经过障碍点。输出所有可走的方向路径序列。

思路:标准dfs回溯。。。开始用pair和map解决负坐标问题,可老是TLE,最后参考了网上的把代码都向上平移了100个距离。

(1)输出:将所有障碍点加上100,超出地图范围的不要!

(2)枚举:从原点开始枚举4个方向,除了原点4个方向都可以走外,其他点都是根据上一个点的方向后,排除当前不能走的后剩下的继续递归。

(3)判断:枚举每个点时预先将上点坐标和本次的走的步数和方向进行查找此过程时候出现障碍物,出现则不走,否则走。

(4)剪枝:预先打步数表,sum[n]代表第n次最多走几步,如果当前坐标到原点的距离(|x|+|y|) 大于 最多还能走的步数(sum[20] - sum[k]) 即可剪枝!

参考:JeraKrs博客

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <cstring>
using namespace std;
const int maxn = 250;
const int expand = 100;
//typedef pair<int,int> coor;
//map<coor,int>g;
int g[maxn][maxn];
int n,path[maxn],ans;
char dir[] = {"ensw"};
int dx[] = {1,0,0,-1};
int dy[] = {0,1,-1,0};
int sum[21];
inline bool exceed(int x,int y){//超出地图范围
    if(abs(x)+expand > maxn || abs(y)+expand > maxn) return true;
    return false;
}
inline bool judge(int x,int y,int st,int d){//判断走的过程是否穿越障碍物
    for(int i=0;i<st;i++){
        x += dx[d]; y += dy[d];
        if(exceed(x,y)) continue;
        if(g[x+expand][y+expand] == -1) return false;
    }
    return true;
}
void dfs(int x,int y,int steps,int prev){
    if(abs(x) + abs(y) > sum[20] - sum[steps]) return;//剪枝:当前位置到原点距离非常大直接退出
    if(steps > n){
        if(x == 0 && y == 0){
            for(int i=1;i<steps;i++) printf("%c",dir[path[i]]);printf("\n");
            ans++;
        }
        return;
    }
    //int prev = path[steps-1];
    for(int i=0;i<4;i++){
       if(i == prev || i+prev == 3) continue;//排除直走和后退
       int tx = x + steps*dx[i] , ty = y + steps*dy[i];
       if(judge(x,y,steps,i) && !g[expand+tx][expand+ty]){
            path[steps] = i;//保存方向
            g[expand+tx][expand+ty] = 1;
            dfs(tx,ty,steps+1,i);
            g[expand+tx][expand+ty] = 0;
       }
    }
}
int main()
{
    int t,k,u,v;
    for(int i=1;i<=20;i++) sum[i] = sum[i-1] + i;//将所有步数打表用于剪枝
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&k);
        memset(g,0,sizeof(g));
        for(int i=0;i<k;i++){
            scanf("%d%d",&u,&v);
            if(exceed(u,v)) continue;
            g[u+expand][v+expand] = -1;
        }
        path[0] = -3;
        ans = 0;
        dfs(0,0,1,-3);
        printf("Found %d golygon(s).\n\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值