• POJ_3740——精确覆盖问题,DLX模版


    花3小时打上的注释,分享给大家。。

      1 #include <cstdio>
      2 #include <cstring>
      3 const int MAXR = 20;
      4 const int MAXC = 310;
      5 const int MAXN = MAXR * MAXC + MAXC;
      6 const int INF = MAXR * 10;
      7 
      8 int n, m;
      9 int L[MAXN], R[MAXN], U[MAXN], D[MAXN];
     10 int C[MAXN], O[MAXN], S[MAXN], H[MAXR];
     11 int nodeNumber;
     12 
     13 void init()
     14 {
     15     for(int i=0;i<=m;++i)
     16     {
     17         L[i] = i - 1;
     18         R[i] = i + 1;
     19         U[i] = i;
     20         D[i] = i;
     21         C[i] = i;
     22         O[i] = 0;
     23         S[i] = 0;
     24     }
     25     L[0] = m;
     26     R[m] = 0;
     27     nodeNumber = m + 1;
     28     memset(H, 0, sizeof(H));
     29 }
     30 
     31 void insert(int i, int j)
     32 {
     33     if(H[i])   //判断这一行中有没有节点 
     34     {
     35         L[nodeNumber] = L[H[i]];    //如果有节点了,就添加一个节点,并把左指针指向第一个节点的未被更新的左指针,也就是新节点的左指针 
     36         R[nodeNumber] = H[i];       //右指针指向该行第一个节点 
     37         L[R[nodeNumber]] = nodeNumber;    //更新第一个节点的左指针 
     38         R[L[nodeNumber]] = nodeNumber;    //更新前一个节点的右指针 
     39     }
     40     else
     41     {
     42         L[nodeNumber] = nodeNumber;    //如果没有节点就添加一个节点,并把左右指针指向自己 
     43         R[nodeNumber] = nodeNumber;
     44         H[i] = nodeNumber;             //标记为该行第一个节点
     45     }
     46     
     47     U[nodeNumber] = U[j];  //节点的上指针指向上面一个节点 
     48     D[nodeNumber] = j;     //节点的下指针指向对应的列表头 
     49     U[D[nodeNumber]] = nodeNumber;  //更新列表头的上指针指向当前节点 
     50     D[U[nodeNumber]] = nodeNumber;  //更新上一个节点的下指针指向当前节点
     51     
     52     C[nodeNumber] = j;  //记录列号 
     53     O[nodeNumber] = i;  //记录行号
     54     
     55     ++ S[j];         //S当中记录着每列节点的个数 
     56     ++ nodeNumber;   //新建一个节点 
     57 }
     58 
     59 void remove(int c)
     60 {
     61     L[R[c]] = L[c];  //右节点的左指针指向原节点的左节点 
     62     R[L[c]] = R[c];  //左节点的右指针指向原节点的右节点 
     63     for(int i=D[c];i!=c;i=D[i])     //从该列往下第一个节点开始往下遍历 
     64     {
     65         for(int j=R[i];j!=i;j=R[j]) //从当前行的第二个节点往右遍历,因为列已经被删除,所以第一个节点不用管 
     66         {
     67             U[D[j]] = U[j];   //把前面删除的列上符合要求的行也删除 
     68             D[U[j]] = D[j];
     69             -- S[C[j]];       //把相应列上对应的节点数也减少1个 
     70         }
     71     }
     72 }
     73 
     74 void resume(int c)
     75 {
     76     for(int i=U[c];i!=c;i=U[i])  //从该列最后一个节点往上遍历,不遍历列表头节点 
     77     {
     78         for(int j=L[i];j!=i;j=L[j]) //从该行最后一个节点往左遍历,不遍历第一个节点 
     79         {
     80             ++ S[C[j]];    //列上面恢复一个节点,节点数也+1 
     81             D[U[j]] = j;   //恢复行 
     82             U[D[j]] = j;
     83         }
     84     }
     85     R[L[c]] = c;  //最后恢复列 
     86     L[R[c]] = c;
     87 }
     88 
     89 bool dfs(int k)
     90 {
     91     if(!R[0])  //如果列表头上第一个节点的右指针为0,即所有列都被删除,则搜索完成 
     92     {
     93         return true;
     94     }
     95     //因为要输出最优秀(最少的行)的答案,每次都要优先搜索列节点最少的列 
     96     int count = INF, c;
     97     for(int i=R[0];i;i=R[i])  //从第一个列开始,直到右指针指向列头,即逐列遍历 
     98     {
     99         if(S[i] < count)   //找到节点最少的列 
    100         {
    101             count = S[i];  //count里面放最少的节点数 
    102             c = i;         //把该列做标记 
    103             if(1 == count) //该列节点,为最少允许的情况直接算是找到了,跳出 
    104             {
    105                 break;
    106             }
    107         }
    108     }
    109     remove(c);    //把该列和列上符合要求的行删除
    110     for(int i=D[c];i!=c;i=D[i])  //在被删除的列上,往下遍历 
    111     {
    112         for(int j=R[i];j!=i;j=R[j]) //对应的行上往右遍历 
    113         {
    114             remove(C[j]);  //如果行上有符合要求的列,删了 
    115         }
    116         if(dfs(k+1)) //递归层数+1,深度搜索 
    117         {
    118             return true;
    119         }
    120         for(int j=L[i];j!=i;j=L[j]) //从该行最后一个节点往左遍历,第一个节点不遍历 
    121         {
    122             resume(C[j]);  //恢复之前删除的*行* 
    123         }
    124     }
    125     resume(c); //递归跳出,恢复之前删除的列 
    126     return false;
    127 }
    128 
    129 int main()
    130 {
    131     int t;
    132     while(~scanf("%d%d",&n,&m))
    133     {
    134         init();
    135         /*
    136         printf("L\tR\tU\tD\tC\tO\n");
    137         for(int i=0;i<=m;i++)
    138             {
    139                printf("%d\t",L[i]);
    140                printf("%d\t",R[i]);
    141                printf("%d\t",U[i]);
    142                printf("%d\t",D[i]);
    143                printf("%d\t",C[i]);
    144                printf("%d\t\n",O[i]);
    145             }      
    146         */
    147         for(int i=1;i<=n;++i)
    148         {
    149             for(int j=1;j<=m;++j)
    150             {
    151                 scanf("%d", &t);
    152                 if(t)
    153                 {
    154                     insert(i, j);   //建立抽象十字链表 
    155                 }
    156             }
    157         }
    158         bool flag = true;
    159         for(int i=1;i<=m;++i)
    160         {
    161             if(S[i] == 0)  //如果有一列没有一个节点,直接失败 
    162             {
    163                 flag = false;
    164                 break;
    165             }
    166         }
    167         if(flag && dfs(0))    //进入深度搜索 
    168         {
    169             printf("Yes, I found it\n");
    170         }
    171         else
    172         {
    173             printf("It is impossible\n");
    174         }
    175     }
    176     return 0;
    177 }
    178 /*
    179 6 7
    180 0 0 1 0 1 1 0
    181 1 0 0 1 0 0 1
    182 0 1 1 0 0 1 0
    183 1 0 0 1 0 0 0
    184 0 1 0 0 0 0 1
    185 0 0 0 1 1 0 1
    186 */
    ——现在的努力是为了小时候吹过的牛B!!
  • 相关阅读:
    自动化测试如何解析excel文件?
    Unittest加载执行用例的方法总结
    pytest进阶之配置文件
    [编程题] 把二叉树打印成多行
    [编程题]求1+2+3+....n
    [编程题]-[位运算技巧系列]不用加减乘除做加法
    [编程题]数值的整数次方
    [编程题]构建乘积数组
    [编程题]变态跳台阶
    [编程题][剑指 Offer 10- II. 青蛙跳台阶问题]
  • 原文地址:https://www.cnblogs.com/pingge/p/3131980.html
Copyright © 2020-2023  润新知