UVa 225 Golygons 题解

难度:β

建议用时:40 min

关于这道题目的背景在维基百科上有。很神奇。

但是我们的这道题没有那么多考虑。上来直接东南西北狂搜一通就好了。

算法很简单,直接上过程。

首先确定 “东”“南”“西”“北” 对应的英文字母 “e”“s”“w”“n”。

因为题目还说不能后退,所以要把后退的方向也处理出来。”东“对”西“ 等等。

因为出发点在(0,0),又可以往负的方向走,为了用数组存,我们给每个坐标加一个 buf = 105 的东西,保证坐标都非负。

1 blocks[x+buf][y+buf] = 1;

另外因为对一个方向最多只走 buf 个距离,因此在范围外的障碍物就 pass 掉。

1 if(abs(x) > buf || abs(y) > buf) continue;

下面直接东南西北搜。

 1 void dfs(int curDepth, int curX, int curY, int lastDir) {
 2     if(curDepth == lastLenth) {
 3         if(curX == startX && curY == startY) {
 4             output();
 5             total++;
 6         }
 7         return;
 8     }
 9
10     if(is_time_to_go_back(curDepth, curX, curY)) return;
11
12     for(int dir = 0; dir <= 3; dir++) {
13         int newX = curX + dx[dir]*(curDepth+1);
14         int newY = curY + dy[dir]*(curDepth+1);
15
16         if(abs(newX) > buf || abs(newY) > buf) continue;
17         if(block_in_the_way(curX, curY, newX, newY)) continue;
18         if(dir + lastDir == 3 || dir == lastDir) continue;
19         if(vis[newX+buf][newY+buf]) continue;
20
21         vis[newX+buf][newY+buf] = 1;
22         path[curDepth] = dir;
23         dfs(curDepth+1, newX, newY, dir);
24         vis[newX+buf][newY+buf] = 0;
25     }
26 }

注意这里的细节:

1 if(dir + lastDir == 3 || dir == lastDir) continue;

回头看:

1 const char directions[] = {‘e‘, ‘n‘, ‘s‘, ‘w‘};

哦!好妙!判断方向方便很多!小技巧。

作为一到剪枝题,这里的重点就在剪枝函数 “is_time_to_go_back” 上。

先分析一下。要想在规定的步数走回原点,容易想到要限制不能走太远。因为走的距离和是有限的。而这里的距离是以曼哈顿距离为参考的。所以自然要在这方面剪枝。

1 bool is_time_to_go_back(int curDepth, int curX, int curY) {
2     int manhattan_dist = abs(curX) + abs(curY);
3     int remain_dist = S[lastLenth] - S[curDepth];
4     if(remain_dist < manhattan_dist) return true;
5     return false;
6 }

这个 “S” 就是等差数列前 n 项和。计算出还可以走多少曼哈顿距离。

构造 “S” :

1 void init() {
2     S[0] = 0;
3     for(int i = 1; i <= 20; i++) S[i] = S[i-1] + i;
4 }

这题还需判断有没有障碍物,上 code :

bool block_in_the_way(int sx, int sy, int tx, int ty) {
    if(sx > tx) swap(sx, tx);
    if(sy > ty) swap(sy, ty);
    for(int x = sx; x <= tx; x++) {
        for(int y = sy; y <= ty; y++) {
            if(blocks[x+buf][y+buf]) return true;
        }
    }
    return false;
}

大概想法就是枚举路上的每一个点,判断是不是障碍物。

注意要保证 x 和 y 的递增。否则枚举会出问题。

总体过程结束了。

这题回头看没有什么难点,曼哈顿距离就是求绝对值之和。不知道还有没有更高效的剪枝方法。

不明白的请留言。

如果你对这篇文章感兴趣,请关注我,我会定期(每天)更新文章。希望一起交流哈~

2018-01-22 00:02:04 (好晚啊)

原文地址:https://www.cnblogs.com/Alrond/p/8326152.html

时间: 2024-10-28 16:27:56

UVa 225 Golygons 题解的相关文章

UVA - 225 Golygons

题意:求从原点开始依次走1,2...n步后到回到原点的方案数,其中不能经过障碍,每次必须左右拐 思路:一个比较简单的DFS,结果做了好久 #include <iostream> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; const int MAXN = 250; const int Add = 100; int n, ans; int G[MA

UVa 10152 - ShellSort 题解

按他的方法排序,每次移动一个数到顶点,排成需要的序列. Problem D: ShellSort He made each turtle stand on another one's back And he piled them all up in a nine-turtle stack. And then Yertle climbed up. He sat down on the pile. What a wonderful view! He could see 'most a mile! T

[UVA - 12034] Race 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接(vjudge):https://vjudge.net/problem/UVA-12034 题目大意: A,B两人赛跑,可能出现三种情况: 1.A,B并列第一 2.A第一,B第二 3.B第一,A第二 现在有N个人赛跑,问可能出现多少种情况,答案对10056取模. 输入格式: 第一行一个数字T(1<=T<=1000),表示数据组数. 接下来T行,每行一个数字N(1<=N<=1000),表示赛跑的人数. 输出

UVA 1642 MagicalGCD 题解

题面 本题是一道区间最大公约数的模板题: 如果N^2暴力的话当然会超时,所以我们要发掘出区间gcd的特点: 设gcd[i]表示区间[1,i]的最大公约数: 我们可以发现,从一个点i到1之间的所有区间的gcd均满足gcd[j]=GCD(gcd[j-1],a[j]); 由于gcd的性质,所以gcd[]是单调不增的: 接着,我们似乎发现了一个更神奇的事情,g[]中不同的值最多有log(max(a[i]))个: 换句话说,虽然g[]数组的长度为n,但在以上两个条件的限制下,最多仅仅有logA个值发生改变

UVa 1329 - Corporative Network Union Find题解

UVa的题目好多,本题是数据结构的运用,就是Union Find并查集的运用.主要使用路径压缩.甚至不需要合并树了,因为没有重复的连线和修改单亲节点的操作. 郁闷的就是不太熟悉这个Oj系统,居然使用库中的abs就会WA,自己写了个abs小函数就过了. 题目:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4075 #include <s

UVa - 457 - Linear Cellular Automata 题解

本题大概题意: 给出一个数组DNA,包含10个数值,如:DNA[10] = {0,1,2,3,,1,2,3,0,1,2}所有数值应该不大于3. 给出一行40个字符的字符串: 空格代表0, '.'代表1,'x'代表2,'W'代表3. 相邻三个数值(或两个数值)相加得到的数作为DNA的下标,然后取DNA数组改下标的数值为新的值.产生新的字符串. 好难说清楚,看原文吧,的确是很难理解的题目: http://uva.onlinejudge.org/index.php?option=com_onlinej

UVa 11988 - Broken Keyboard (a.k.a. Beiju Text) 题解

刘汝佳的题目,悲剧文本 -_-||| 这里使用vector<string>容器倒置记录数据,然后从后面输出就可以了. 难度就是不知道这样的文档到底哪里是开始输出,故此使用动态管理内存的容器比较好做. 增加了io处理的O(n)算法也没有上榜,郁闷. #include <stdio.h> #include <vector> #include <string> using std::vector; using std::string; const int MAX_

UVa 127 - &quot;Accordian&quot; Patience POJ 1214 链表题解

UVa和POJ都有这道题. 不同的是UVa要求区分单复数,而POJ不要求. 使用STL做会比较简单,这里纯粹使用指针做了,非常麻烦的指针操作,一不小心就错.调试起来还是非常费力的 本题理解起来也是挺费力的,要搞清楚如何模拟也不容易啊,读题要很仔细. 纯指针的操作挺快的吧.不过POJ 0ms,而UVa就0.2左右了. 三相链表: 1 只要有叠起来的牌,那么就使用一个down指针指向下面的牌就可以了. 2 使用双向链表,可以方便前后遍历. 3 记得有了更新牌之后,又要重新开始检查是否需要更新牌,这是

UVa 10305 - Ordering Tasks 拓扑排序题解

Topological Sort题解.本题是简单的入门题目. Topological Sort的思想很简单,就是按没有入度的点,先输出,然后删除这个点的出度.然后输出下一组没有入度的点. 如何实现也是很简单的: 这里使用邻接表,建图的时候反过来建图,建立一个入度邻接表. 然后使用一个vis数组,记录访问过的节点,也可以根据这个信息知道哪些是已经输出的点,这个时候这些点的入度可以不算为当前入度了. #include <stdio.h> #include <vector> using