UVa225 - Golygons

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值