Loading

2020.08.09 周作业简要题解

周作业 ×

玄学搜索剪枝大赏 √

\[\huge\text{POJ3278} \]

题意

给定 \(x\)\(y\),每次有三种操作 \(x:=x-1\)\(x:=x+1\)\(x:=x\times 2\),需要保证 \(x \geq 1\)

\(x\) 至少要几步才能变成 \(y\)只能修改 \(x\)

\(1 \leq x,y \leq 10^5\)

题解

BFS 即可。考虑剪枝掉 \(x > 10^5\) 的状态,这样保证了复杂度。

证明:如果我们需要让 \(x\) 乘上 \(2\) 后大于 \(10^5\),然后通过连续地减去 \(1\) 使 \(x\) 等于 \(y\)。设当 \(x>10^5\) 后需要减去 \(p\) 次才能到达 \(y\),显然可以在执行乘 \(2\) 操作前将 \(x\) 减去 \(\dfrac p2\) ,后者的总操作次数比前者更优。

所以一定存在一个最优解,该解中的 \(x\) 在任意时刻均 \(\leq 10^5\)

\[\huge\text{UVA524} \]

题意

输入正整数 \(n\),把整数 \(1,2,\dots ,n\) 组成一个环,使得相邻两个整数之和均为素数。输出时,从整数 \(1\) 开始逆时针排列。同一个环恰好输出一次。

\(n \leq 16\)

题解

DFS 模板。值得一提的是,需要在搜索时剪枝掉当前所有不合法的状态,不能确定了环上每一个数之后再检查,这样复杂度会卡满 \(O(n!)\),没有任何通过的机会。

\[\huge\text{UVA725} \]

题意

求出所有 \(0,1,2,...,9\) 的排列 \(a,b,c,d,e,f,g,h,i,j\),使得

\[\dfrac{\overline{abcde}}{\overline{fghij}}=N \]

允许出现前导 \(0\)

\(2 \leq n \leq 79\)

题解

DFS 模板题。因为 \(10!=3628800\) 并不大,所以我们可以枚举所有排列,判断其是否合法。

\[\huge\text{UVA11059} \]

题意

给定长为 \(n\) 的整数数组 \(S\),求出其连续子序列中乘积最大的,并输出其乘积。连续子序列可以为空,此时乘积为 \(0\)

\(-10 \leq S_i \leq 10,1 \leq n \leq 18\)

题解

显然可以枚举连续子序列的起点和终点,计算即可。

答案最大为 \(10^{18}\),需要使用 \(64\) 位整形存储。

\[\huge\text{UVA10976} \]

题意

给定正整数 \(k\),求所有满足

\[\dfrac 1x + \dfrac 1y= \dfrac 1k \]

且满足 \(x \geq y\) 的正整数对 \((x,y)\)

\(1 \leq k \leq 10^4\)

题解

考虑推式子。

\[\dfrac 1x + \dfrac 1y = \dfrac 1k \]

\[\dfrac 1x = \dfrac 1k - \dfrac 1y \]

\[\dfrac 1x = \dfrac{y-k}{ky} \]

\[x=\dfrac{ky}{y-k} \]

即:枚举 \(y(y \in [k+1,2k])\),看 \(x\) 是否为整数即可。

\(y < k\)\(\dfrac 1y\geq k\);当 \(y>2k\),因为 \(x \geq y\)\(\dfrac 1x+\dfrac 1y<\dfrac 1k\),显然无法取到正整数解。

\[\huge\text{UVA129} \]

题意

如果一个字符串不包含两个相邻且相等的重复子串,那么它被称之为困难的串。

形式上来讲,对于字符串 \(S(|S|=n)\),如果不存在 \(1 \leq l \leq \left \lfloor \dfrac n2\right \rfloor\)\(2l \leq x \leq n\) 使得 \(S_{x-2l+1...x-l}=S_{x-l+1...x}\),那么 \(S\) 被称作困难的串。

求字典序第 \(n\) 小,且只包含前 \(L\) 个大写字母的字符串。

\(n > 0, L \leq 26\)

题解

考虑 DFS 剪枝。对于字符串 \(S(|S=n|)\),当我们加入 \(S_{n+1}\) 时,只需要考虑第二个重复子串的末尾为 \(S_{n+1}\) 的相邻重复子串,因为前面的相邻重复子串如果存在,便已经在之前剪枝掉了。

\[\huge\text{POJ1915} \]

题意

给定 \(n\times n\) 的国际象棋棋盘,求出骑士从某个点走到另外一个点的最小步数。

\(4 \leq n \leq 300\)

题解

BFS 即可。

双向 BFS 的正确做法是:起点出发的待扩展点存储在队列 \(Q_1\),终点出发的存储在队列 \(Q_2\),如果 \(|Q_1|<|Q_2|\),拓展一层 \(Q_1\),否则拓展一层 \(Q_2\)

然而我的做法:将起点终点标记上不同的颜色,扔到队列里跑。这优化了个京华啊(捂脸)。

\[\huge\text{UVA10603} \]

题意

给定容量为 \(a,b,c\) 升的三个无刻度杯子,最初只有第三杯装满了水。求至少需要倒多少水才能使某个杯子恰有 \(d\) 升水。

如果不可能,找到最大的 \(d'<d\),使得可以使某个杯子恰有 \(d'\) 升水,并求出至少需要倒多少水才能使某个杯子恰有 \(d'\) 升水。

\(0 \leq a,b,c,d\leq 200\)

题解

直接搜索状态太多(\(200^3=8\cdot 10^6\)),因为有多组数据,所以复杂度无法接受。

观察到三个杯子水量总和一定,记录前两个杯子里的水量即可求出第三个杯子的水。这样就只有 \(40000\) 个状态,可以接受。

\[\huge\text{UVA140} \]

题意

给定 \(n\) 个点的无向图。将这些点排列,得到 \(p_1,p_2,...,p_n\)。定义 \(p\) 的带宽为图中边的端点在排列里的最大距离。求带宽最小的排列。

\(1 \leq n\leq 8\)

题解

枚举全排列即可。

介绍 STL 函数: std::next_permutation(*start,*end)

如果存在下一个排列,返回非零值并将 [start,end) 转换为下一个排列。否则返回 \(0\)

\[\huge\text{UVA1354} \]

题意

\(s\) 个挂坠,重量为 \(w_1,w_2,...,w_s\)。有一些长度为 \(1\) 的木条,木条的每一端可以挂上挂坠,还可以连接另一根木条,但不能有某一端不放任何东西。木条长度不计。

你需要设计一种方案,使得能挂上所有的挂坠,且平衡(设左右侧到支点长分别为 \(m,n\),重量为 \(a,b\),那么必须满足 \(ma=nb\))。你需要使这个方案在长度不超过 \(r\) 的前提下长度最大。

\(0 <r<10,1\leq s \leq 6,w_i \leq 1000\)

题解

根据题意,先搜索出所有挂东西的方案,然后我们调整支点的位置,来使该方案平衡,并计算出该方案的总长度。

容易观察到,任何方案可以转化为一棵二叉树,叶节点是挂坠。木条可以看作一条边,木条的端点为非叶节点。

具体来讲,记录该方案的最左侧点 \(v_l\) 和最右侧点 \(v_r\)。设根节点的位置为 \(0\),如果某个点在根节点左侧,则其位置为负,否则其位置为正。自顶向下考虑,对于每个非叶节点,设其左侧的总重量为 \(w_l\),右侧的总重量为 \(w_r\),那么左右两侧到该点的距离分别为 \(\dfrac{w_r}{w_l+w_r},\dfrac{w_l}{w_l+w_r}\)。注意,某一侧偏重的时候,它到该点的距离近,这很容易被没有学过物理的人所混淆。那么记录该点的位置 \(mid\),则左右两侧的位置分别为 \(mid-\dfrac{w_r}{w_l+w_r},mid+\dfrac{w_l}{w_l+w_r}\)。可以通过简单的取最小值 / 最大值来维护 \(v_l,v_r\)。最后 \(v_r-v_l\) 即为该方案的长度。

\[\huge\text{UVA1601} \]

题意

有一个 \(n \times m\) 的迷宫,其中有一些地方不能走。最外层一定不能走。

\(x\) 个鬼在移动。每一秒,它们可以到达新的位置或不动,但必须遵循以下原则:

  • 没有两个鬼在一个位置
  • 没有两个鬼在某一秒交换了位置

给出鬼的位置和它们要去的终点,问至少需要多少秒才能使所有鬼到达自己要去的终点。保证有解

\(4 \leq n,m \leq 16,1 \leq x \leq 3\)

题解

可以给可用的格子标号,然后设计状态 \((a,b,c)\),表示三个鬼分别在标号为 \(a,b,c\) 的格子的最小步数。

观察到可用的格子不超过 \(16^2-16\times 4+4\leq 196\),所以我们可以把状态 \((a,b,c)\) 表示为一个二进制数,其高八位代表 \(a\),中间八位代表 \(b\),最低的八位代表 \(c\)。搜索即可。

观察到鬼的数量可能小于 \(3\)。这种情况下,将 \(b/c\) 表示为两个不同且大于最大标号的数即可,但不要超过 \(256\)

输入使用 fgets,否则会 TLE。

\[\huge\text{UVA11212} \]

题意

给定一个 \(1\)\(n\) 的排列 \(p\)。每次操作可以选择一个连续子序列,将其剪切到另外一个位置。求至少需要几次操作能将其变成 \(1,2,...,n\)

\(1 \leq n \leq 9\)

题解

考虑 IDA*。定义 \(p_i\) 的后继为 \(p_i+1\)。观察到,一次操作至多改变 \(3\) 个数的后继。最好的情况下,至多使 \(3\) 个数的后继变为正确的。显然,我们不会将一个数已经正确的后继破坏掉。设计估价函数:\(h() = \dfrac {\text{dif}}{3}\)。其中 \(\text{dif}\) 表示不正确的后继数量。

那么,我们可以估计该状态是否合法:\(\text{nowstep}+h() \leq \text{maxstep}\)。值得一提的是,\(h()\) 可能不是整数,这个时候需要将不等式等价变形为 \(\text{nowstep} \times 3+\text{dif} \leq \text{maxstep}\times 3\)

\[\huge\text{UVA12325} \]

题意

给定容量为 \(n\) 的背包,有两种物品,均有无限个,体积和价值分别为 \(S_1,V_1,S_2,V_2\),求最大价值。

\(1 \leq n,S_i,V_i \leq 10^9\)

题解

首先,知道了某一种物品的个数,显然可以计算出另一种物品的个数。

\(S_1<S_2\)

如果 \(\dfrac {n}{S_2} < \sqrt{n}\),那么可以在不高于 \(O(\sqrt{n})\) 的时间内求出所有可能的第二种物品个数。

否则,从 \(0\)\(S_1\) 枚举可能的第二种物品个数,从 \(0\)\(S_2\) 枚举可能的第一种物品的个数。显然,这仍然不高于 \(O(\sqrt{n})\)

正确性证明:如果第一种物品的性价比比第二种高,那么如果第二种物品有 \(S_1\) 件,显然可以通过将其中 \(S_1 \times S_2\) 的体积替换为 \(S_2\) 件第一种物品来获得更高的性价比。反之亦然。

\[\huge\text{UVA1374} \]

题意

最初,你的手上有一个正整数 \(x\)。你可以选择一个已经计算出 \(x^a\),如果当前手上的数为 \(x^b\),那么你可以选择计算出 \(x^{a+b}\) 或 计算出 \(x^{b-a}\)(当 \(b>a\) 时),都需要花费一次操作。求至少需要几次操作才能计算出 \(x^n\)

\(1 \leq n \leq 1000\)

题解

考虑倍增,次数显然不超过 \(11\)

迭代加深搜索。对于限制为 \(m\) 步,当前准备使用第 \(x\) 步的状态,考虑剪枝:

  • 当前的幂 \(b\) 经过 \(m-x+1\) 次平方后无法到达 \(n\),即 \(b\times 2^{m-x+1}<n\)

  • 当前的幂 \(b\) 已经被计算过

即可。

\[\huge\text{LOJ10022} \]

题意

\(\dfrac{a}{b}\) 分解为几个分子为 \(1\) 的不同分数之和。保证给出数据有解,且分母最大的分数分母 \(\leq 10^7\)

给出分数个数最小的解。如果仍有多解,给出最大分母最小的解;如果仍有多解,给出任意解。

题解

迭代加深搜索。

令枚举的分母 \(x\) 单调递增,如果剩余的分数大小为 \(\dfrac{a}{b}\),对于限制为 \(m\) 步,当前准备使用第 \(i\) 步的状态,考虑剪枝:

  • 如果 \(i=m\)\(a \neq 1\),那么当前状态无法得出解
  • \(x\in [\ \ \max\{lst+1,\dfrac ba +1\},(m-i+1)\times b \div a\ \ )\),其中 \(lst\) 表示上一次枚举到的分母

证明第二个剪枝。对于 \(x\) 的下界,显然应该使 \(\dfrac 1x<\dfrac ab\)。推一下可以得到 \(\dfrac ba < x\),即 \(x \geq \dfrac ba +1\)

对于 \(x\) 的上界:因为后面的分数都比 \(\dfrac 1x\) 小,那么如果后面的分数全部选 \(\dfrac 1x\) 仍然无法大于 \(\dfrac ab\),即:

\[\dfrac 1x \times (m-i+1)\leq \dfrac ab \]

\[\dfrac{m-i+1}{x}\leq \dfrac{a}{b} \]

\[b(m-i+1)\leq ax \]

\[b(m-i+1)\div a\leq x \]

\[x \geq b(m-i+1)\div a \]

反过来讲,当 \(x < b(m-i+1)\div a\) 时,才可能存在可行解。

注意通分时可能会溢出,需要使用 long long

posted @ 2020-08-08 13:57  Meatherm  阅读(223)  评论(2编辑  收藏  举报