zoukankan      html  css  js  c++  java
  • 2020.08.09 周作业简要题解

    周作业 ×

    玄学搜索剪枝大赏 √

    [huge ext{POJ3278} ]

    题意

    给定 (x)(y),每次有三种操作 (x:=x-1)(x:=x+1)(x:=x imes 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 ext{UVA524} ]

    题意

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

    (n leq 16)

    题解

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

    [huge ext{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 ext{UVA11059} ]

    题意

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

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

    题解

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

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

    [huge ext{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 1ygeq k);当 (y>2k),因为 (x geq y)(dfrac 1x+dfrac 1y<dfrac 1k),显然无法取到正整数解。

    [huge ext{UVA129} ]

    题意

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

    形式上来讲,对于字符串 (S(|S|=n)),如果不存在 (1 leq l leq left lfloor dfrac n2 ight floor)(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 ext{POJ1915} ]

    题意

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

    (4 leq n leq 300)

    题解

    BFS 即可。

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

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

    [huge ext{UVA10603} ]

    题意

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

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

    (0 leq a,b,c,dleq 200)

    题解

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

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

    [huge ext{UVA140} ]

    题意

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

    (1 leq nleq 8)

    题解

    枚举全排列即可。

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

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

    [huge ext{UVA1354} ]

    题意

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

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

    (0 <r<10,1leq 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 ext{UVA1601} ]

    题意

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

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

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

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

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

    题解

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

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

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

    输入使用 fgets,否则会 TLE。

    [huge ext{UVA11212} ]

    题意

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

    (1 leq n leq 9)

    题解

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

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

    [huge ext{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 imes S_2) 的体积替换为 (S_2) 件第一种物品来获得更高的性价比。反之亦然。

    [huge ext{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 imes 2^{m-x+1}<n)

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

    即可。

    [huge ext{LOJ10022} ]

    题意

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

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

    题解

    迭代加深搜索。

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

    • 如果 (i=m)(a eq 1),那么当前状态无法得出解
    • (xin [ max{lst+1,dfrac ba +1},(m-i+1) imes 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 imes (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 aleq x ]

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

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

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

  • 相关阅读:
    kali长时间未使用导致数字签名过期无法更新源解决办法
    4.爬虫去重策略
    3.编码问题
    kalinux 五笔安装
    ★★★kalinux 常用命令
    安装vm tools时出现如下问题 The path "/usr/bin/gcc" is not valid path to the
    kalinux实现自适用全屏、与物理主机共享文件方法
    wifi pj WiFiPhisher 安装使用
    条款20:在传递对象的时候尽量用reference-to-constent来代替,pass-by-value
    条款19:定义class就相当于定义一个个的内置类型
  • 原文地址:https://www.cnblogs.com/liuzongxin/p/13457311.html
Copyright © 2011-2022 走看看