[题解]UVA1603 破坏正方形 Square Destroyer

是一道启发式搜索和位运算,剪枝的杂合题目。

要学好搜索,搜索是很重要的算法。那些很厉害的选手都是搜索打得好的。(By Instructor Li)

题目分析

  • 首先,\(N≤5\),且边数是\(2N(N+1)≤60\)。在这样的小数据下可以位运算优化。
  • 启发式搜索,设计估价函数\(G(X)\)。要求低于真实代价。下面是一种方法:
  • 对于每一个正方形,删除它的所有边。重复这个操作知道没有正方形。操作的次数就是估价
  • 然而,仅仅这样不足以过掉这题。还需要优化。

判断正方形

  • 在纸上推导一下,或者直接找规律,可以得到:
  • 如果一条横放的火柴编号为\(X_0\),
  • \(X_0\)左下方的\(L\)根火柴分别是:$ X_i=X + (2i-1) N + i - 1,(0<i<L)$。
  • 那么正方形的左边界确定了,右边界的编号就是左边界加上边长。
  • 预处理出所有的正方形,并且按照从小到大的顺序。原因后面会说
  • 这样在DFS函数里减少了判断正方形的开销

位运算的技巧

  • 用==unsigned long long==存储一个正方形的边的编号。
  • 利用==&==,==|==运算符可以完成判断正方形是否存在,在一个状态上增加边等操作。具体实现方法是
  • #define Mark(X,K) (X=X|((Ull)1<<((K)-1)))
    #define Del(X,K) (X&(~((Ull)1<<((K)-1))))
    #define Check(X,K) (X&(1<<((K)-1)))
  • 三个宏定义的作用分别是:标记数==X==的第==K==位,删除标记和检查是否有标记。

减枝

  • 从预处理的正方形里,挑选最小的完整的一个,枚举删除它的边。
  • 因为前面的正方形已经残缺不全了,那么不必再纠缠。同时因为从小到大的顺序,搜索树的分支会更少。
  • 使用迭代加深。

附上部分代码

  • 预处理正方形:下面的代码返回了以==X==为初始,以==K==为边长的正方形。并且把正方形的起始边、长度保存下来。

    Ull Get (int X , int K) {
      Ull Ans = 0 ;
      int Dlt = K * ((N << 1) + 1) ;
      for (int i = X ; i < X + K ; ++ i) Mark (Ans , i) , Mark (Ans , Dlt + i) ;
      for (int i = 1 ; i <= K; ++ i)
          Mark (Ans , X + (2*i-1) * N + i - 1) , Mark (Ans ,X + (2*i-1) * N + i - 1 + K) ;
      return Ans ;
    }
  • 估价函数:利用位运算从一个状态中拆除整个正方形:
    int G (Ull X) {
      int Ans = 0 ;
      for (int i = 1 ; i <= Cnt ; ++ i) {
          if( (S[i] & X) == S[i]) {
              ++ Ans ;
              X = X & (~S[i]) ;
          }
      }
      return Ans ;
    }
  • 搜索:因为前期做好了工作,搜索函数内部很简洁。
    void DFS (Ull X , int Stp , int Des) {
    
      int Now = G(X) ;
      if (Now + Stp > Ans) return ;
      if (Now == 0 || Fl) {
          Fl = true ;
          return ;
      }
    
    while ((S[Des] & X) != S[Des]) ++ Des ;
    for (int i = F[Des] ; i < F[Des] + Len[Des] ; ++ i) {
          if (Check (X , F[Des]))DFS (Del (X , F[Des]) , Stp + 1 , Des + 1) ;
          if (Check (X , Len[Des] * ((N << 1) + 1) + i))
                DFS (Del ( X , Len[Des] * ((N << 1) + 1) + i) , Stp + 1 , Des + 1);
      }
    for (int i = 1 ; i <= Len[Des]; ++ i) {
      if (Check (X , F[Des] + (2*i-1) * N + i - 1))
              DFS( Del (X , F[Des] + (2*i-1) * N + i - 1) , Stp + 1 , Des + 1) ;
      if (Check (X , F[Des] + (2*i-1) * N + i - 1 + Len[Des]))
              DFS (Del (X , F[Des] + (2*i-1) * N + i - 1 + Len[Des] ), Stp + 1 , Des + 1) ;
      }
    }

注意清空数组

原文地址:https://www.cnblogs.com/bj2002/p/11367518.html

时间: 2024-10-18 12:17:55

[题解]UVA1603 破坏正方形 Square Destroyer的相关文章

UVa1603 - Square Destroyer

题意: 给定一个火柴棒拼成的方格阵,然后去掉一些火柴棒,问至少再去掉几根火柴棒能够让图中一个正方形都没有. 思路: 1. 由于题目中给定了 n 的范围,2 * n * (n + 1) <= 60 -> 所以能够保证所有的火柴用 __int64 的位运算表示; 2. 问题的关键在于如何生成火柴构成的方阵,以及生成方阵之后如何去搜索; 3. 启发式函数 h 的计算需要考量:如果删除了某个方阵的一个边,则能够保证 h(s1) <= h(s2) + C(s1, s2),其中 C(s1, s2)

(中等) POJ 1084 Square Destroyer , DLX+可重复覆盖。

Description The left figure below shows a complete 3*3 grid made with 2*(3*4) (=24) matchsticks. The lengths of all matchsticks are one. You can find many squares of different sizes in the grid. The size of a square is the length of its side. In the

POJ 1084 Square Destroyer【舞蹈链】【重复覆盖】

建模很容易就能说清楚,但我一直想不出来. 要问为什么的话可能是因为这题要先预处理出来所有正方形,而我没做过要预处理的舞蹈链的题.所以想不到. 那就是预处理出来所有正方形,用一个long long来表示一个正方形,这个正方形有没有包含id这条边就用 (1<<id)&num判断.那怎么预处理所有正方形呢,枚举边长1-n的正方形,然后再枚举这个正方形左上方的顶点就能做出来. 然后就能建模了,火柴是行,所有按现有火柴能拼出来的正方形是列,与其说是精准覆盖倒也可以说是全部破坏. http://e

[DLX重复覆盖] poj 1084 Square Destroyer

题意: n*n的矩形阵(n<=5),由2*n*(n+1)根火柴构成,那么其中会有很多诸如边长为1,为2...为n的正方形,现在可以拿走一些火柴,那么就会有一些正方形被破坏掉. 求在已经拿走一些火柴的情况下,还需要拿走至少多少根火柴可以把所有的正方形都破坏掉. 思路: 对于每个位置遍历所有可能的边长,确定这个边长下的正方形的边对应的都是数字几,并且把正方形从1开始编号. 然后根据编号,把正方形和数字建边记录方便下面建图. 然后以火柴棍为行,正方形为列,建立dancing link 然后求解. 这里

[DLX反复覆盖] poj 1084 Square Destroyer

题意: n*n的矩形阵(n<=5),由2*n*(n+1)根火柴构成,那么当中会有非常多诸如边长为1,为2...为n的正方形,如今能够拿走一些火柴,那么就会有一些正方形被破坏掉. 求在已经拿走一些火柴的情况下.还须要拿走至少多少根火柴能够把全部的正方形都破坏掉. 思路: 对于每一个位置遍历全部可能的边长,确定这个边长下的正方形的边相应的都是数字几,而且把正方形从1開始编号. 然后依据编号,把正方形和数字建边记录方便以下建图. 然后以火柴棍为行,正方形为列,建立dancing link 然后求解.

【POJ】1084 Square Destroyer

1. 题目描述由$n \times n, n \in [1, 5]$的正方形由$2 \times n \times (n+1)$根木棍组成,可能已经有些木棍被破坏,求至少还需破坏多少木根,可以使得不存在任何正方形?2. 基本思路这是一道非常有趣的题目,可以使用IDA*解也可以用DLX解.可以试试5 0这组数据比较两者的性能差异.(1) IDA*使用IDA*处理,是因为最后的解的范围一定不是很大,因为数据很小.至多也就60根木棍.首先可以预处理分别对正方形和木棍进行编号,进而预处理破坏每根木棍可以

poj 1084 Square Destroyer dlx解重复覆盖

分析: 将问题转化为重复覆盖问题,DancingLink解决. 代码: //poj 1084 //sep9 #include <iostream> using namespace std; const int maxN=10024; const int maxL=128; int L[maxN],R[maxN],U[maxN],D[maxN]; int C[maxN],H[maxN]; int S[maxN],A[maxN],X[maxN]; bool makeup[maxL][maxL];

UVA 1603 Square Destroyer

题意: 给定一个火柴棒拼成的方格阵,然后去掉一些火柴棒,问至少再去掉几根火柴棒能够让图中一个正方形都没有. 思路: 1. 由于题目中给定了 n 的范围,2 * n * (n + 1) <= 60 -> 所以能够保证所有的火柴用 long long的位运算表示; 2. 启发式函数 h 的计算需要考量:如果删除了某个方阵的一个边,则能够保证 h(s1) <= h(s2) + C(s1, s2),其中 C(s1, s2) = 1,h(s1) - h(s2) <= 1; 3. 各种位运算的

【POJ 1084】 Square Destroyer

[题目链接] http://poj.org/problem?id=1084 [算法] 迭代加深 [代码] #include <algorithm> #include <bitset> #include <cctype> #include <cerrno> #include <clocale> #include <cmath> #include <complex> #include <cstdio> #inclu