DLX重复覆盖

const int maxn = 15*15+10;
const int maxm = 15*15+10;
const int maxnode = maxn*maxm;
const int inf  = 0x3f3f3f3f;
struct DLX
{
    int n,m,sizes,H[maxn],S[maxm],ansd;
    int U[maxnode],D[maxnode],L[maxnode],R[maxnode],Row[maxnode],Col[maxnode];
    void init( int _n , int _m )
    {
        n = _n;
        m = _m;
        for ( int i=0 ; i<=m ; i++ )
        {
            S[i] = 0;
            U[i] = D[i] = i;
            L[i] = i-1;
            R[i] = i+1;
        }
        R[m] = 0; L[0] = m; sizes = m;
        for ( int i=1 ; i<=n ; i++ ) H[i] = -1;
    }
    void Link( int r , int c )
    {
        ++S[Col[++sizes]=c];
        Row[sizes] = r;
        D[sizes] = D[c];
        U[D[c]] = sizes;
        U[sizes] = c;
        D[c] = sizes;
        if ( H[r]<0 ) H[r] = L[sizes] = R[sizes] = sizes;
        else
        {
            R[sizes] = R[H[r]];
            L[R[H[r]]] = sizes;
            L[sizes] = H[r];
            R[H[r]] = sizes;
        }
    }
    void Remove( int c )
    {
        for ( int i=D[c] ; i!=c ; i=D[i] )
            L[R[i]] = L[i],R[L[i]] = R[i];
    }
    void Resume( int c )
    {
        for ( int i=U[c] ; i!=c ; i=U[i] )
            L[R[i]] = R[L[i]] = i;
    }
    bool v[maxm];
    int f()
    {
        int ret = 0;
        for ( int c=R[0] ; c!=0 ; c=R[c] ) v[c] = true;
        for ( int c=R[0] ; c!=0 ; c=R[c] )
            if ( v[c] )
            {
                ret++; v[c] = false;
                for ( int i=D[c] ; i!=c ; i=D[i] )
                    for ( int j=R[i] ; j!=i ; j=R[j] )
                        v[Col[j]] = false;
            }
        return ret;
    }
    void Dance( int d )
    {
        if ( d+f()>=ansd ) return;
        if ( R[0]==0 )
        {
            if ( d<ansd ) ansd = d;
            return;
        }
        int c = R[0];
        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] )
        {
            Remove( i );
            for ( int j=R[i] ; j!=i ; j=R[j] ) Remove( j );
            Dance( d+1 );
            for ( int j=L[i] ; j!=i ; j=L[j] ) Resume( j );
            Resume( i );
        }
    }
}dlx;
int a[20][20],id[20][20];
int main()
{
    for ( int n,m ; scanf ( "%d%d" , &n , &m )==2 ; )
    {
        int sz = 0; memset ( id , 0 , sizeof(id) );
        for ( int i=0 ; i<n ; i++ )
            for ( int j=0 ; j<m ; j++ )
            {
                scanf ( "%d" , &a[i][j] );
                if ( a[i][j]==1 ) id[i][j] = ++sz;
            }
        dlx.init( n*m , sz );
        sz = 1; int n1,m1;
        scanf ( "%d%d" , &n1 , &m1 );
        for ( int i=0 ; i<n ; i++ )
            for ( int j=0 ; j<m ; j++ )
            {
                for ( int x=0 ; x<n1&&i+x<n ; x++ )
                    for ( int y=0 ; y<m1&&j+y<m ; y++ )
                        if ( id[i+x][j+y] ) dlx.Link( sz , id[i+x][j+y] );
                sz++;
            }
        dlx.ansd = inf;
        dlx.Dance(0);
        printf ( "%d\n" , dlx.ansd );
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值