UVa 307 Sticks 题解

Posted alrond

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa 307 Sticks 题解相关的知识,希望对你有一定的参考价值。

难度:β-

建议用时:30 min

实际用时:40 min

题目:??

代码:??

 

这题是我目前做的最快的一题。

因为我看了别人的题解

代码照着别人抄的,当然做的快。

我现在有些不好意思了。

 

现在只是在别人的基础上说些我的理解。

这题用 DFS 很好说。然而剪枝我开始没想到。事后想一想也有道理。

因为这题设计到了长度拼凑问题,根据经验,这类题要用剪枝。像 Egyptian Fractions 这种题目就是列子。

 

那么,下面就是确定搜索状态的时候了。

 

我因为很水,想了半天不知道怎样用搜索状态。然后一看题解就懂了。

 

状态有 3 个变量,一个存目前已经拼凑完整(相对迭代深搜限定的长度)的木棍组数,一个存当前枚举到的木棍编号,

一个存目前要拼凑的长度已经累积到多少了。

 

好吧,这三个变量就是这题搜索需要的所有信息了。当然还有每根木棍的长度。等等。

这个搜索状态的寻找,我只能说凭经验了。

 

下面就是搜索了。

先给一个伪码吧。

 1 bool solve(int cnt, int cur, int len) {
 2     if (cnt * lth == sum) return true;
 3     
 4     for (int i = cur; i < n; i++) {
 5         if (lenth[i] + len < lth) {
 6             vis[i] = 1;
 7             if (solve(cnt, i+1, len+lenth[i])) return true;
 8             vis[i] = 0;
 9         }
10         
11         if (lenth[i] + len == lth) {
12             vis[i] = 1;
13             if (solve(cnt+1, 0, 0)) return true;
14             vis[i] = 0;
15         }
16     }
17 
18     return false;
19 }

这是想得到正确答案的必要步骤。

算法是:

1)如果当前状态下已经把所有木棍凑整了,那么显然找到解了,返回

2)枚举每一木棍,如果用过了,跳过。

3)如果没有用过,尝试把这根木棍加到目前累计的长度上。如果加上后的长度比目标的小,就尝试继续加。

4)否则,如果刚好就加到了目标长度,尝试进行下一组的拼凑。

在整个过程中,牵涉到了 vis 数组的使用。一根木棍不能用两次。

 

(这里先事先提醒一下,我们枚举木棍时,是一遍一遍从长木棍枚举到短木棍(之前读入后排个序),在没有凑完整一组之前,我们是不会往回枚举的。

了解这一点可以更容易理解下面剪枝的方案。)

 

这个算法足以得到正确答案了。(测的是样例)

然而,如果不适当剪枝,100 ms 瞬间飙到 860 ms。不过还是可以 AC 的。

 

不管怎样,上面提到的那位大神想到了 3 个剪枝办法。

 

1)最最重要的,如果当前的木棍已经用过了,或是上一根木棍的长度和当前木棍的长度相等,然而上一根没用,那么这一根也不可能会用到。跳过。

if (vis[i] || (i && lenth[i] == lenth[i-1] && !vis[i-1])) continue;

为什么呢?因为上面提到的,我们枚举木棍是从大到小递减的(不是严格的),如果排在之前的木棍和自己的长度一摸一样,然而没选它,怎么可能选自己?

如果不选它而选自己,那么后面搜索时就一定会有使自己凑整的方案。

然而,作为大哥,怎么能让小弟抢走自己的份额?大哥一定会先抢走,对吧?所以大哥没有的,小弟怎么会有?

(我不会告诉你我是从我的化学老师那里学来的江湖口吻)(~~)

 

2)次重要的,如果当前处理的是第一根木棍,然而这一根选了后没有解,那么不管怎么选后面的,这一根是不会被选的,与他同长度的也不会被选。直接跳过,返回。

1 if (len == 0) return false;

3)次次重要的,如果当前选择的木棍刚好可以凑整了,然而下一组和下下一组和下下下一组的木棍不知怎么就凑不整了,那么也可以返回。

return false;

(在这里放代码好像没什么用)(没有上下文啊!)

这个剪枝我还没想好怎样证明。放这里,打个记号 ??

 

好了,总之借助于其他大神的剪枝方案,我把这题还是水过去了。

 

说实话,这题剪枝还是有些不寻常的。(就目前我的水平来说)

 

2018-01-29

 

以上是关于UVa 307 Sticks 题解的主要内容,如果未能解决你的问题,请参考以下文章

uva307小木棍 Sticks [dfs搜索]

UVa307 Sticks (DFS+剪枝)

UVA10003 Cutting Sticks

Cutting Sticks UVA - 10003

uva 10003 Cutting Sticks 区间dp

UVA - 10003 —— Cutting Sticks