淺入 dancing links x(舞蹈鏈算法)


abastract:利用dancing links 解決精確覆蓋問題,例如數獨,n皇后問題;以及重復覆蓋問題。

要學習dacning links 算法,首先要先了解該算法適用的問題,精確覆蓋問題和重復覆蓋問題等,下面先了解精確覆蓋問題和重復覆蓋問題。

精確覆蓋問題

何為精確覆蓋問題

  在一個全集X中若干子集的集合為S,精確覆蓋(Exactcover)是指,S的子集S*,滿足X中的每一個元素在S*中恰好出現一次。

定義 

  滿足以下條件的集合為一個精確覆蓋: 
    S*中任意兩個集合沒有交集,即X中的元素在S*中出現最多一次 
    S*中集合的全集為X,即X中的元素在S*中出現最少一次 
    合二為一,即X中的元素在S*中出現恰好一次。
  舉例
  令={N,O,E,P}是集合X={1,2,3,4}的一個子集,並滿足: 
    N={} 
    O={1,3} 
    E={2,4} 
    P={2,3}. 
    其中一個子集{O,E}是X的一個精確覆蓋,因為O={1,3}而E={2,4}的並集恰好是X={1,2,3,4}。同理,{N,O,E}也是X.的一個精確覆蓋。空集並不影響結論。

精確覆蓋問題的表示方式

  一般的,我們用一個集合s包含s中的元素的單向關系表示精確覆蓋問題。常用的有以下兩種方法:

  • 矩陣表示法

  包含關系可以用一個關系矩陣表示。.矩陣每行表示S的一個子集,每列表示X中的一個元素。矩陣行列交點元素為1表示對應的元素在對應的集合中,不在則為0。 

  通過這種矩陣表示法,求一個精確覆蓋轉化為求矩陣的若干個行的集合,使每列有且僅有一個1。同時,該問題也是精確覆蓋的典型例題之一。

  下表為其中一個例子:

   

  S*={B,D,F}便是一個精確覆蓋。

  • 圖論表示法

  可將精確覆蓋問題轉化為一個二分圖,左側為集合,右側為元素,左側集合若與右側元素有包含關系則連邊,通過將左側節點與其所有邊保留與否求解一個右側的每一個節點恰好有一條邊的匹配。

重復覆蓋問題

  即選取一個01矩陣中的幾行,使這幾行組成的新矩陣的每一列至少有一個1。 該問題在精確覆蓋問題上減少了一個約束條件。

  接下來就是dancing links x算法了。


 

  Dancing Links X 算法

歷史

  X算法是高德納提出的解決精確覆蓋問題的算法,而dancing links X算法則是DonKnuth(《計算機程序設計藝術》的作者)提出的對X算法的一種高效實現,這種實現建立在如上所說的矩陣表示法上。

算法思想

  由如上精確覆蓋問題的矩陣表示法中,我們知道dancing links x 是用來求解一個 01矩陣中選取哪幾行可以使得這幾行每一列都有且僅有一個1(就是每個元素在這幾個子集里有且僅有出現過一次)。

  先不管他的實際意義,我們需要做的就是在一個01矩陣的選取某幾行使之符合上述條件。

  我們很容易就想到枚舉,然后判斷符不符合條件,但是這個做法實在是太消耗時間。

  dacing links x就是一個高效的求解該類問題的算法,而這種算法,基於交叉十字循環雙向鏈的數據結構。  

  例如:如下的矩陣

     clip_image002

  就包含了這樣一個集合(第1、4、5行)

  如何利用給定的矩陣求出相應的行的集合呢?我們采用回溯法

  clip_image002

  先假定選擇第1行,如下所示:

     clip_image002[4]

  如上圖中所示,紅色的那行是選中的一行,這一行中有3個1,分別是第3、5、6列。

  由於這3列已經包含了1,故,把這三列往下標示,圖中的藍色部分。藍色部分包含3個1,分別在2行中,把這2行用紫色標示出來

  根據定義,同一列的1只能有1個,故紫色的兩行,和紅色的一行的1相沖突。

  那么在接下來的求解中,紅色的部分、藍色的部分、紫色的部分都不能用了,把這些部分都刪除,得到一個新的矩陣

  clip_image002[6]

  行分別對應矩陣1中的第2、4、5行

  列分別對應矩陣1中的第1、2、4、7列  

  於是問題就轉換為一個規模小點的精確覆蓋問題 

  在新的矩陣中再選擇第1行,如下圖所示

     clip_image002[8]

  還是按照之前的步驟,進行標示。紅色、藍色和紫色的部分又全都刪除,導致新的空矩陣產生,而紅色的一行中有0(有0就說明這一列沒有1覆蓋)。說明,第1行選擇是錯誤的 

  那么回到之前,選擇第2行,如下圖所示  

     clip_image002[10]

  按照之前的步驟,進行標示。把紅色、藍色、紫色部分刪除后,得到新的矩陣

  clip_image002[12]

  行對應矩陣2中的第3行,矩陣1中的第5行

  列對應矩陣2中的第2、4列,矩陣1中的第2、7列

   由於剩下的矩陣只有1行,且都是1,選擇這一行,問題就解決

  於是該問題的解就是矩陣1中第1行、矩陣2中的第2行、矩陣3中的第1行。也就是矩陣1中的第1、4、5行()

(例子引用自http://www.cnblogs.com/grenet/p/3145800.html)

  而對於重復覆蓋問題,在選定某一行之后只需刪除該行含1的所在列,並不需要再刪除所在列上含1的行。


 

2016-08-21 21:00:15

Example1:HUST  1017

  裸精確覆蓋問題,問題如下:

1017 - Exact cover

題目描述:

  There is an N*M matrix with only 0s and 1s, (1 <= N,M <= 1000). An exact cover is a selection of rows such that every column has a 1 in exactly one of the selected rows. Try to find out the selected rows.輸入There are multiply test cases. First line: two integers N, M; The following N lines: Every line first comes an integer C(1 <= C <= 100), represents the number of 1s in this row, then comes C integers: the index of the columns whose value is 1 in this row.輸出First output the number of rows in the selection, then output the index of the selected rows. If there are multiply selections, you should just output any of them. If there are no selection, just output "NO".

樣例輸入

6 7

3 1 4 7

2 1 4

3 4 5 7

3 3 5 6

4 2 3 6 7

2 2 7

樣例輸出

3 2 4 6

提示來源

dupeng

 

  裸精確覆蓋問題,直接用dancing links 做。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #define clr(x) memset(x,0,sizeof(x))
  5 #define clrlow(x) memset(x,-1,sizeof(x))
  6 #define maxnode 1001010
  7 #define maxn    1010
  8 using namespace std;
  9 struct DLX{
 10     int n,m; 
 11     int U[maxnode],D[maxnode],L[maxnode],R[maxnode],col[maxnode],row[maxnode];
 12     int H[maxn];
 13     int ansed,ans[maxn],size;
 14     void init(int _n,int _m)
 15     {
 16         n=_n;
 17         m=_m;
 18         for(int i=0;i<=m;i++)
 19         {
 20             U[i]=i;
 21             D[i]=i;
 22             L[i]=i-1;
 23             R[i]=i+1;
 24             col[i]=i;
 25             row[i]=0;
 26         }
 27         L[0]=m;
 28         R[m]=0;
 29         size=m;
 30         clrlow(H);
 31         clr(ans);
 32         ansed=0;
 33         return ;
 34     }
 35     void push(int r,int c)
 36     {
 37         size++;
 38         D[size]=D[c];
 39         U[size]=c;
 40         U[D[c]]=size;
 41         D[c]=size;
 42         row[size]=r;
 43         col[size]=c;
 44         if(H[r]<0)
 45         {
 46             H[r]=size;
 47             R[size]=L[size]=size;
 48         }
 49         else
 50         {
 51             L[size]=H[r];
 52             R[size]=R[H[r]];
 53             L[R[H[r]]]=size;
 54             R[H[r]]=size;
 55         }
 56     }
 57     void del(int c)
 58     {
 59         R[L[c]]=R[c];
 60         L[R[c]]=L[c];
 61         for(int i=D[c];i!=c;i=D[i])
 62             for(int j=R[i];j!=i;j=R[j])
 63             {
 64                 D[U[j]]=D[j];
 65                 U[D[j]]=U[j];
 66             }
 67         return ;
 68     }
 69     void reback(int c)
 70     {
 71         for(int i=U[c];i!=c;i=U[i])
 72             for(int j=L[i];j!=i;j=L[j])
 73             {
 74                 D[U[j]]=j;
 75                 U[D[j]]=j;
 76              } 
 77         R[L[c]]=c;
 78         L[R[c]]=c;
 79         return ;
 80     }
 81     bool dancing(int dep)
 82     {
 83         if(R[0]==0)
 84         {
 85             ansed=dep;
 86             return true;
 87         }
 88         int c=R[0];
 89         del(c);
 90         for(int i=D[c];i!=c;i=D[i])
 91         {
 92             ans[dep]=row[i];
 93             for(int j=R[i];j!=i;j=R[j])
 94                 del(col[j]);
 95             if(dancing(dep+1))
 96                 return true;
 97             for(int j=L[i];j!=i;j=L[j])
 98                 reback(col[j]);
 99         }
100         return false;
101     }
102 }dlx;
103 int main()
104 {
105     int n,m,p,k;
106     while(scanf("%d%d",&n,&m)==2)
107     {
108         dlx.init(n,m);
109         for(int i=1;i<=n;i++)
110         {
111             scanf("%d",&p);
112             for(int j=1;j<=p;j++)
113             {
114                 scanf("%d",&k);
115                 dlx.push(i,k);
116             }    
117         }
118         if(!dlx.dancing(0))
119             printf("NO\n");
120             else
121             {
122                 printf("%d",dlx.ansed);
123                 for(int i=0;i<dlx.ansed;i++)
124                     printf(" %d",dlx.ans[i]);
125                 printf("\n");
126             }
127     }
128     return 0;
129  } 

 

除此之外,運用這個dancing links 的這個模板,還可以解決數獨,n皇后問題。

淺談數獨解法  

  我們在做數獨時一般會使用枚舉法。在某個格子枚舉當前情況下的所有可填入數字,而在枚舉其中一個可填入數字后遞歸到下一層,也就是下一個格子,枚舉上一個格子數字確定下來的九宮格在該格子的所有可填入數字,以此類推。直到九宮格完全填滿時,這時候的解為該九宮格的一個可行解,可繼續遞歸返回上一層尋找下一個可行解。這個做法效率不錯,但是若直接枚舉,寫起來就又臭又長(好吧我承認其實DLX也挺長的),若九宮格過於稀疏,該做法的時間效率也會指數級上升。我們選擇用DLX把每一個已填格子和未填格子的信息轉化成行,接下來dance一遍找出符合條件的行,再轉化回九宮格信息,就是一個可行解了。最多729行進行DLX(9*9*9,后面你會明白的),速度較直接枚舉也快很多,除去DLX的結構體,其他代碼長度也比直接枚舉短很多(打模板比較快hhh)

  那么怎么把九宮格上的信息轉化成行呢? 首先數獨中可行的解需滿足:每一行,每一列,每一個宮里面不能有相同的數字,且只能使用1-9這九個數字。

  把它轉化為符合精確覆蓋問題的條件,即為:

  1. 每一個格只能填一個數字。
  2. 每個數字在每一行只能出現一次。
  3. 每個數字在每一列只能出現一次。
  4. 每個數字在每一宮只能出現一次。

  對於第一個條件:

  第一列表示填入(11)這一格。

  第二列表示填入(12)這一格。

  第三列表示填入(13)這一格。

      ……

  第(m-1)*9+n列表示填入(m,n)這一格。(1<=m<=9,1<=n<=9

  ……

  9*9-1列表示填入(9,8)這一格。

  9*9列表示填入(9,9)這一格。

  設inf1=81

  以此類推……

  第二個條件:

  第inf+1列表示在第一行填入1

  第inf+2列表示在第一行填入2

  第inf+3列表示在第一行填入3

  ……

  第inf+(n-1)*9+m列表示在第n行填入m1<=n<=91<=m<=9)。

  ……

  第inf+9*9表示在第九行填入9

  設inf2=inf1+81;

    對於第三個條件也是如此,inf3=inf2+81;

  對於第四個條件,inf4=inf3+81;

 至此,已經把所有的條件都轉化成了列。

 而對於一個有數字的格子(假設位於(m,n)數字為k,位於第p宮)只需把它轉化為一行,該行於(m-1)*9+n,inf1+(m-1)*9+k,inf2+(n-1)*9+k,inf3+(p-1)*9+k這四列為1,其余為0。

 對於一個沒有數字的格子(假設位於(m',n')第p'宮),則需把他轉化為九行,分別代表在這一格填入1-9各個數字,每一列的填列原理和有數字的格子一樣。

 在把所有的格子轉化完畢后,先把所有確定的有數字的格子的行以及該行含1的列以及該列上含1的行從矩陣中刪除,然后dance一遍,找出符合的行,再把行轉化成每個格子的信息,填入九宮格中,就是符合的一個解了。

2016-08-27 17:07:53

n皇后解法

  類似於數獨問題,在n皇后問題中,不沖突的n皇后的棋盤上符合以下五個個條件:

  1. 每一個格子最多只能有一個皇后。
  2. 每一行最多只能有一個皇后。
  3. 每一列最多只能有一個皇后。
  4. 每一個從左上往右下的斜邊最多只能有一個皇后。
  5. 每一個從右上往左下的斜邊最多只能有一個皇后。

  這五個條件看起來不太好用dlx的做法去做,但如果把整個棋盤中有皇后的位置用1表示,沒有皇后的位置用1表示,則可以轉化為:

  1. 每個格子只能填一個數字。
  2. 每一行有且僅能填一個1。
  3. 每一列有且僅能填一個1。
  4. 每一個從左上往右下的斜邊有且僅能填一個1。
  5. 每一個從右上往左下的斜邊有且僅能填一個1。

   按照數獨的過程進行DLX,找出填1的行數大於等於n的解。等於n的解即為n皇后問題的解,大於n的解刪去幾行使填1的行數為n即為n皇后問題的解。


 

重復覆蓋問題

  顧名思義,即為在01矩陣中,選出幾行,使得在這幾行組成的新矩陣中,每一列都有1。

  下面是hdu上一個重復覆蓋的二分問題,並且給出重復覆蓋問題的代碼部分:

 Example2:hdu 2295

Radar

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2280    Accepted Submission(s): 897

Problem Description
N cities of the Java Kingdom need to be covered by radars for being in a state of war. Since the kingdom has M radar stations but only K operators, we can at most operate K radars. All radars have the same circular coverage with a radius of R. Our goal is to minimize R while covering the entire city with no more than K radars.
 
Input
The input consists of several test cases. The first line of the input consists of an integer T, indicating the number of test cases. The first line of each test case consists of 3 integers: N, M, K, representing the number of cities, the number of radar stations and the number of operators. Each of the following N lines consists of the coordinate of a city.
Each of the last M lines consists of the coordinate of a radar station.

All coordinates are separated by one space.
Technical Specification

1. 1 ≤ T ≤ 20
2. 1 ≤ N, M ≤ 50
3. 1 ≤ K ≤ M
4. 0 ≤ X, Y ≤ 1000
 
Output
For each test case, output the radius on a single line, rounded to six fractional digits.
 
Sample Input
1 3 3 2 3 4 3 1 5 4 1 1 2 2 3 3
 
Sample Output
2.236068
 
Source
 

該題用二分查找radar的半徑,然后用重復覆蓋的DLX進行最多選取k行該半徑是否完全覆蓋所有城市的判斷(f()函數和dep一起判斷),最后精確到小數點后六位。

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#define clr(x) memset(x,0,sizeof(x))
#define clrlow(x) memset(x,-1,sizeof(x))
#define maxnode 3000
#define maxn 60
using namespace std;
struct DLX//dancing links 
{
    int U[maxnode],D[maxnode],L[maxnode],R[maxnode],col[maxnode],row[maxnode];//元素上下左右對應列對應行的指針 
    int S[maxn],H[maxn],V[maxn];//S為每列元素個數,H指向每行末尾的元素,V是dep()函數的標記數組。 
    int n,m,size,all;//all為解的行數的最大值 
    void init(int _n,int _m,int _all)
    {
        n=_n;
        m=_m;
        all=_all;
        for(int i=0;i<=m;i++)
        {
            L[i]=i-1;
            R[i]=i+1;
            U[i]=i;
            D[i]=i;
            row[i]=0;
            col[i]=i;
        }
        clr(S);
        clrlow(H);
        L[0]=m;
        R[m]=0;
        size=m;
        return ;
    }
    //初始化 
    void push(int r,int c)
    {
        D[++size]=D[c];
        col[size]=U[size]=c;
        U[D[c]]=size;
        D[c]=size;
        row[size]=r;
        S[c]++;
        if(H[r]<0) 
        {
            H[r]=L[size]=R[size]=size;
        }
        else
        {
            L[size]=H[r];
            R[size]=R[H[r]];
            L[R[H[r]]]=size;    
            R[H[r]]=size;
        }    
        return ;
    }
    //加入元素 
    void del(int c)
    {
        S[col[c]]--;
        for(int i=D[c];i!=c;i=D[i])
            {
                R[L[i]]=R[i];
                L[R[i]]=L[i];
                S[col[i]]--;
            }
        return ;
    }
     //刪除一列 
     void reback(int c)
     {
         for(int i=U[c];i!=c;i=U[i])
         {
             S[col[R[L[i]]=L[R[i]]=i]]++;
         }
         S[col[c]]++;
         return ;
     }
     //恢復一列 
     int  dep( )
     {
         clr(V);
         int deep=0;
         for(int i=R[0];i!=0;i=R[i])
         if(!V[i])
         {
             deep++;
             for(int j=D[i];j!=i;j=D[j])
                 for(int k=R[j];k!=j;k=R[k])
                         V[col[k]]=1;
         }
         return deep;
     }
     //之后到達的最大深度
     //d為當前深度 
     bool dancing(int d)
     {
         if(d+dep()>all) return false;
         int c=R[0];
         if(c==0) 
         {
             return d<=all;
        }
        for(int i=R[0];i!=0;i=R[i])
            if(S[i]<S[c])
                c=i;
         for(int i=D[c];i!=c;i=D[i])
         {
             del(i);
             for(int j=R[i];j!=i;j=R[j])
                 del(j);
             if(dancing(d+1)) return true;
             for(int j=L[i];j!=i;j=L[j])
                 reback(j);
             reback(i);
         }
         return false;
     }
     //dancing 
}dlx;
struct point
{
    int x,y;
}station[maxn],city[maxn]; 
double dis(point a,point b)
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int main()
{
    int n,m,k,kase;
    double lt,rt,mid;
    double eps=1e-8;
    scanf("%d",&kase);
    while(kase--)
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&city[i].x,&city[i].y);
        for(int i=1;i<=m;i++)
            scanf("%d%d",&station[i].x,&station[i].y);
        lt=0;
        rt=1e8;
        while(rt-lt>=eps)
        {
            dlx.init(m,n,k);
            mid=(rt+lt)/2;
            for(int i=1;i<=m;i++)
                for(int j=1;j<=n;j++)
                 if(dis(city[j],station[i])<mid*mid-eps)
                     dlx.push(i,j);
            if(dlx.dancing(0))
                rt=mid-eps;
            else
                lt=mid+eps;
        }
        printf("%.6lf\n",lt);
    }
    return 0;
}

 

 FZU上一道練手題

Problem 1686 神龍的難題

Accept: 717    Submit: 2140
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

 

這是個劍與魔法的世界.英雄和魔物同在,動盪和安定並存.但總的來說,庫爾特王國是個安寧的國家,人民安居樂業,魔物也比較少.但是.總有一些魔物不時會進入城市附近,干擾人民的生活.就要有一些人出來守護居民們不被魔物侵害.魔法使艾米莉就是這樣的一個人.她騎着她的坐騎,神龍米格拉一起消滅干擾人類生存的魔物,維護王國的安定.艾米莉希望能夠在損傷最小的前提下完成任務.每次戰斗前,她都用時間停止魔法停住時間,然后米格拉他就可以發出火球燒死敵人.米格拉想知道,他如何以最快的速度消滅敵人,減輕艾米莉的負擔.

 Input

 

數據有多組,你要處理到EOF為止.每組數據第一行有兩個數,n,m,(1<=n,m<=15)表示這次任務的地區范圍. 然后接下來有n行,每行m個整數,如為1表示該點有怪物,為0表示該點無怪物.然后接下一行有兩個整數,n1,m1 (n1<=n,m1<=m)分別表示米格拉一次能攻擊的行,列數(行列不能互換),假設米格拉一單位時間能發出一個火球,所有怪物都可一擊必殺.

 

 Output

 

輸出一行,一個整數,表示米格拉消滅所有魔物的最短時間.

 

 Sample Input

4 4 1 0 0 1 0 1 1 0 0 1 1 0 1 0 0 1 2 2 4 4 0 0 0 0 0 1 1 0 0 1 1 0 0 0 0 0 2 2

 Sample Output

4 1

 Source

FOJ月賽-2009年2月- TimeLoop

 

依舊是重復覆蓋問題模板

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #define clr(x) memset(x,0,sizeof(x))
  5 #define clrlow(x) memset(x,-1,sizeof(x))
  6 #define maxm (15*15+10)
  7 #define maxn (15*15+10)
  8 #define maxnode maxn*maxm
  9 #define INF 1000000000
 10 using namespace std;
 11 struct DLX
 12 {
 13     int size,n,m;
 14     int D[maxnode],U[maxnode],L[maxnode],R[maxnode],row[maxnode],col[maxnode];
 15     int H[maxn],S[maxm];
 16     int ansed;
 17     void init(int _n,int _m)
 18     {
 19         n=_n;
 20         m=_m;
 21         size=m;
 22         for(int i=0;i<=m;i++)
 23         {
 24             D[i]=i;
 25             U[i]=i;
 26             R[i]=i+1;
 27             L[i]=i-1;
 28             row[i]=0;
 29             col[i]=i;
 30             S[i]=0;
 31         }
 32         L[0]=m; R[m]=0;
 33         for(int i = 1;i <= n;i++)H[i] = -1;
 34         ansed=INF;
 35         return ;
 36     }
 37     void push(int r,int c)
 38     {
 39         ++S[col[++size]=c];
 40         row[size]=r;
 41         D[size]=D[c];
 42         U[size]=c;
 43         U[D[c]]=size;
 44         D[c]=size;
 45         if(H[r]<0)
 46         {
 47             L[size]=R[size]=size;
 48             H[r]=size;
 49         }
 50         else
 51         {
 52             R[size]=R[H[r]];
 53             L[size]=H[r];
 54             L[R[H[r]]]=size;
 55             R[H[r]]=size;
 56         }
 57         return;
 58     }
 59     void del(int p)
 60     {
 61         for(int i=D[p];i!=p;i=D[i])
 62         {
 63             R[L[i]]=R[i];
 64             L[R[i]]=L[i];
 65         }
 66         return ;
 67     }
 68     void remove(int p)
 69     {
 70         for(int i=U[p];i!=p;i=U[i])
 71         {
 72             R[L[i]]=L[R[i]]=i;
 73         }
 74         return ;
 75     }
 76     bool v[maxm];
 77     int dis()
 78     {
 79         int ans=0;
 80         for(int i=1;i<=m;i++) v[i]=0;
 81         for(int i=R[0];i!=0;i=R[i])
 82         if(!v[i])
 83         {
 84             ans++;
 85             for(int j=D[i];j!=i;j=D[j])
 86                 for(int k=R[j];k!=j;k=R[k])
 87                     v[col[k]]=1;
 88         }
 89         return ans;
 90     }
 91     void dancing(int dep)
 92     {
 93         if(dep+dis()>=ansed) return;
 94         if(R[0]==0)
 95         {
 96             if(dep<ansed) ansed=dep;
 97             return ;
 98         }
 99         int c=R[0];
100         for(int i=R[0];i!=0;i=R[i])
101             if(S[i]<S[c])
102                 c=i;
103        for(int i=D[c];i!=c;i=D[i])
104        {
105            del(i);
106            for(int j=R[i];j!=i;j=R[j])
107                 del(j);
108             dancing(dep+1);
109             for(int j=L[i];j!=i;j=L[j])
110                 remove(j);
111             remove(i);
112        }
113        return ;
114     }
115 }dlx;
116 int n,m,n1,m1,a[maxn][maxm],num[maxn][maxm],inf;
117 int main()
118 {
119     while(scanf("%d%d",&n,&m)!=EOF)
120     {
121         inf=0;
122         clr(a);
123         clr(num);
124         for(int i=1;i<=n;i++)
125             for(int j=1;j<=m;j++)
126             {
127                 scanf("%d",&a[i][j]);
128                 if(a[i][j]==1) num[i][j]=(++inf);
129             }
130         dlx.init(n*m,inf);
131         scanf("%d%d",&n1,&m1);
132         inf=0;
133         for(int i=1;i<=n;i++)
134             for(int j=1;j<=m;j++)
135             {
136                 inf++;
137                 for(int k=i;k<i+n1 && k<=n;k++)
138                     for(int l=j;l<j+m1 && l<=m;l++)
139                     if(num[k][l])
140                         dlx.push(inf,num[k][l]);
141             }
142         dlx.dancing(0);
143         printf("%d\n",dlx.ansed);
144     }
145     return 0;
146 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM