UVa 225 - Golygons 解题报告(暴力)

56 篇文章 0 订阅


 Golygons 

Imagine a country whose cities have all their streets laid out in a regular grid. Now suppose that a tourist with an obsession for geometry is planning expeditions to several such cities.

Starting each expedition from the central cross-roads of a city, the intersection labelled (0,0), our mathematical visitor wants to set off north, south, east or west, travel one block, and view the sights at the intersection (0,1) after going north, (0,-1) after going south, (1,0) after going east or (-1,0) after going west. Feeling ever more enthused by the regularity of the city, our mathematician would like to walk a longer segment before stopping next, going two blocks.

What's more, our visitor doesn't want to carry on in the same direction as before, nor visit the same point twice, nor wishes to double back, so will make a 90 tex2html_wrap_inline32 turn either left or right. The next segment should be three blocks, again followed by a right-angle turn, then four, five, and so on with ever-increasing lengths until finally, at the end of the day, our weary traveller returns to the starting point, (0,0).

The possibly self-intersecting figure described by these geometrical travels is called a golygon.

Unfortunately, our traveller will making these visits in the height of summer when road works will disrupt the stark regularity of the cities' grids. At some intersections there will be impassable obstructions. Luckily, however, the country's limited budget means there will never be more than 50 road works blocking the streets of any particular city. In an attempt to gain accountability to its citizens, the city publishes the plans of road works in advance. Our mathematician has obtained a copy of these plans and will ensure that no golygonal trips get mired in molten tar.

Write a program that constructs all possible golygons for a city.

Input

Since our tourist wants to visit several cities, the input file will begin with a line containing an integer specifying the number of cities to be visited.

For each city there will follow a line containing a positive integer not greater than 20 indicating the length of the longest edge of the golygon. That will be the length of the last edge which returns the traveler to (0,0). Following this on a new line will be an integer from 0 to 50 inclusive which indicates how many intersections are blocked. Then there will be this many pairs of integers, one pair per line, each pair indicating the x and y coordinates of one blockage.

Output

For each city in the input, construct all possible golygons. Each golygon must be represented by a sequence of characters from the set {n,s,e,w} on a line of its own, and they should be output in lexicographics order. Following the list of golygons should be a line indicating how many solutions were found. This line should be formatted as shown in the example output. A blank line should appear following the output for each city.

Sample Input

2
8
2
-2 0
6 -2
8
2
2 1
-2 0

Sample Output

wsenenws
Found 1 golygon(s).

Found 0 golygon(s).

Diagram of the 1st City

    解题报告:题意略难懂,要细细读。一位数学家去很多城市里旅游。数学家从0,0点出发,参观很多景点。第一次可以从0,0点向上下左右走一个单位,以后每次走比上次多一个单位,且与上一次走的路线成直角。数学家不能参观之前参观的景点上(但可以直接通过),也不能通过过一些不能通过的点,最终必须回到0,0点。给定最后一段路的距离,以及一些不能通过的点的坐标,求出所有可能的路径,并按照字典序打印出来。
    首先,如果从0,0点出发往上下方向走,那么可以确定1,3,5,7...奇数长度的路程都是在上下方向,2,4,6,8...这些偶数路程都在左右方向。无论是上下方向,还是左右方向,最后都是要回到0,0点,也就是说总位移是0。那么令向上为正,向下为负,必然要使1,3,5,7经过一定的加减运算得到0,2,4,6,8...也是如果。这个结论可以作为剪枝的重要依据。
    其实经过手算可以发现,只有当最后的路程距离是7,8,15,16时,整个路程才能闭合。
    我们可以枚举奇数路程的方向,计算下一步可能的坐标。判断一下剩下的路程的加减结合能否让该坐标到达0。如果不能,说明该点最后必然不能到达0,0点。偶数路程同理。对于剩余的数的加减运算,我们可以先预处理一次。最终路径可以用set保存,使之符合字典序。
    代码如下(C++ 11):
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <iomanip>
using namespace std;
#define ff(i, n) for(int i=0;i<(n);i++)
#define fff(i, n, m) for(int i=(n);i<=(m);i++)
#define dff(i, n, m) for(int i=(n);i>=(m);i--)
#define bit(n) (1LL<<(n))
typedef long long LL;
typedef unsigned long long ULL;
void work();
int main()
{
#ifdef ACM
//    freopen("in.txt", "r", stdin);
#endif // ACM
    work();
}

/***************************************************/

set<int> ss[23];
void init(int n)
{
    ff(i, 23) ss[i].clear();

    ss[n+2].insert(0);
    ss[n+1].insert(0);

    dff(i, n, 1)
    {
        for(int v : ss[i+2])
            ss[i].insert(v+i), ss[i].insert(v-i);
    }
}

int maze[201][201];
char path[22];
int dir;
set<string> ans;

void dfs(int x, int y, int now, int end)
{
    if(now > end)
    {
        if(x == 100 && y == 100)
            ans.insert(path+1);
        return;
    }

    if(now%2 == dir)
    {
        if(ss[now+2].count(x+now-100))
        {
            bool flag = true;
            fff(k, 1, now) if(maze[x+k][y]==1) flag = false;
            if(flag && maze[x+now][y] != 2)
            {
                maze[x+now][y] = 2;
                path[now] = 'e', dfs(x+now, y, now+1, end);
                maze[x+now][y] = 0;
            }
        }

        if(ss[now+2].count(x-now-100))
        {
            bool flag = true;
            fff(k, 1, now) if(maze[x-k][y]==1) flag = false;
            if(flag && maze[x-now][y] != 2)
            {
                maze[x-now][y] = 2;
                path[now] = 'w', dfs(x-now, y, now+1, end);
                maze[x-now][y] = 0;
            }
        }
    }
    else
    {
        if(ss[now+2].count(y+now-100))
        {
            bool flag = true;
            fff(k, 1, now) if(maze[x][y+k]==1) flag = false;
            if(flag && maze[x][y+now] != 2)
            {
                maze[x][y+now] = 2;
                path[now] = 'n', dfs(x, y+now, now+1, end);
                maze[x][y+now] = 0;
            }
        }

        if(ss[now+2].count(y-now-100))
        {
            bool flag = true;
            fff(k, 1, now) if(maze[x][y-k]==1) flag = false;
            if(flag && maze[x][y-now] != 2)
            {
                maze[x][y-now] = 2;
                path[now] = 's', dfs(x, y-now, now+1, end);
                maze[x][y-now] = 0;
            }
        }
    }
}

void work()
{
    int T;
    scanf("%d", &T);
    fff(cas, 1, T)
    {
        int n, point;
        scanf("%d%d", &n, &point);

        memset(maze, 0, sizeof(maze));
        int x, y;
        ff(i, point)
        {
            scanf("%d%d", &x, &y);
            if(abs(x) <= 100 && abs(y) <= 100)
                maze[100+x][100+y] = 1;
        }

        ans.clear();
        if(maze[100][100] == 0 && (n==7 || n==8 || n==15 || n==16))
        {
            init(n);

            path[n+1] = 0;

            dir = 1;
            dfs(100, 100, 1, n);

            dir = 0;
            dfs(100, 100, 1, n);

            for(string str : ans) puts(str.c_str());
        }
        printf("Found %d golygon(s).\n", ans.size());
        puts("");
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值