zoukankan      html  css  js  c++  java
  • 骨牌覆盖小结

    题目链接

    棋盘规模 2*n  (n很大)

    直接找出递推公式用矩阵快速幂求解

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=2;
    const LL mod=19999997;
    LL b[N]= {1,1};        //此处初始化列向量 
    LL hh[N][N]={{1,1},
                 {1,0}
    };
    
    struct Mat
    {
        LL mat[N][N];
        LL* operator [](int x)    //注意这种写法 
        {
            return mat[x];
        }
    } A;
    Mat Mut(Mat a,Mat b)
    {
        Mat c;
        memset(c.mat,0,sizeof(c.mat));
        for(int i=0; i<N; i++)
            for(int k=0; k<N; k++)    if(a[i][k])
                for(int j=0; j<N; j++)
                {
                    c[i][j]+=a[i][k]*b[k][j]%mod;
                    c[i][j]=c[i][j]%mod;
                }
        return c;
    }
    Mat Qpow(Mat a,LL n)
    {
        Mat c;
        for(int i=0; i<N; ++i)
            for(int j=0; j<N; ++j)
                c[i][j]=(i==j);
        for(; n; n>>=1)
        {
            if(n&1) c=Mut(c,a);
            a=Mut(a,a);
        }
        return c;
    }
    LL cal(Mat A,LL n,LL b[])
    {
        Mat A_=Qpow(A,n-1);
        LL ret=A_[0][0]*b[0]+A_[0][1]*b[1];
        return (ret+mod)%mod;
    }
    void init_A()
    {
        for(int i=0; i<N; i++)
            for(int j=0; j<N; j++)
                A[i][j]=hh[i][j];
    }
    
    int main()
    {
        LL n,ans;
        init_A();
        while(cin>>n)
        {
            ans=cal(A,n,b);        //假定下标从第1项开始计数,求第n项 
            cout<<ans<<endl;
        }
    } 
    Lv. 0

    题目链接

    棋盘规模 k*n  (k<=7,n很大)

    利用dfs推出状态转移矩阵(矩阵规模 (2k))

    有一点要注意的是,比如说求的是两列的递推矩阵,那么前一列如果对应位是0,那么递推时,要在该位置横放一个骨牌,使当前列该为1

    然后用矩阵快速幂求解

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=128;
    const LL mod=12357;
    
    int n,k,M;
    
    LL b[N];//= {0,0,0,0,0,0,0,1};        //此处初始化列向量 
    
    struct Mat
    {
        LL mat[N][N];
        LL* operator [](int x)    //注意这种写法 
        {
            return mat[x];
        }
    } A;
    Mat Mut(Mat a,Mat b)
    {
        Mat c;
        memset(c.mat,0,sizeof(c.mat));
        for(int i=0; i<M; i++)
            for(int k=0; k<M; k++)    if(a[i][k])
                for(int j=0; j<M; j++)
                {
                    c[i][j]+=a[i][k]*b[k][j]%mod;
                    c[i][j]=c[i][j]%mod;
                }
        return c;
    }
    Mat Qpow(Mat a,LL n)
    {
        Mat c;
        for(int i=0; i<M; ++i)
            for(int j=0; j<M; ++j)
                c[i][j]=(i==j);
        for(; n; n>>=1)
        {
            if(n&1) c=Mut(c,a);
            a=Mut(a,a);
        }
        return c;
    }
    LL cal(Mat A,LL n,LL b[])
    {
        Mat A_=Qpow(A,n);
        return A_[M-1][M-1];
    }
    void dfs(int pre,int nxt,int col,Mat& A)
    {
        if(col==k)
        {
            A[pre][nxt]=1;
            return ;
        }
        dfs(pre<<1,nxt<<1|1,col+1,A);
        dfs(pre<<1|1,nxt<<1,col+1,A);
        if(col+2<=k)    dfs(pre<<2|3,nxt<<2|3,col+2,A);
    }
    
    
    
    int main()
    {
        while(cin>>k>>n)
        {
            memset(b,0,sizeof(b));
            M=1<<k;
            b[M-1]=1;
            memset(A.mat,0,sizeof(A.mat));
            dfs(0,0,0,A);
            LL ans=cal(A,n,b);        //假定下标从第1项开始计数,求第n项 
            cout<<ans<<endl;
        }
    } 
    Lv. 1

    题目链接

    棋盘规模 n*m  (n,m<=11)

    这时矩阵乘法的复杂度就太大了,可以直接利用利用递推关系搞

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    typedef long long LL;
    const int N=2048;
    
    int n,k,M;
    int A[13][N];
    
    void dfs(int pre,int nxt,int col,int r)
    {
        if(col==k)
        {
            A[r][nxt]+=A[r-1][pre];
            return ;
        }
        dfs(pre<<1,nxt<<1|1,col+1,r);
        dfs(pre<<1|1,nxt<<1,col+1,r);
        if(col+2<=k)    dfs(pre<<2|3,nxt<<2|3,col+2,r);
    }
    
    int main()
    {
        while(cin>>k>>n)
        {
    //        cout<<k<<' '<<n<<endl;
            if(k==0&&n==0)
                break;
            if(k%2&&n%2)
            {
                puts("0");
                continue;
            }
            memset(A,0,sizeof(A));
            if(k>n) swap(k,n); 
            M=1<<k;
            A[0][M-1]=1;
            for(int i=1;i<=n;i++)
                dfs(0,0,0,i);
            LL ans=A[n][M-1];
            cout<<ans<<endl;
        }
    } 
    Lv. 2

    未解决

    题目链接

    棋盘规模 n*m  (n,m<=100)

    唐老师博客

    感觉这题应该不会考吧,出题人似乎是看过论文之后,强行按照论文出了个题

    题目链接

    棋盘规模 n*m  (n,m<=16)

    稳定/免分割线多米诺骨牌的棋盘覆盖问题

    要利用前面的Lv. 2的方法打表,然后用容斥原理解决,目前还不是很懂

  • 相关阅读:
    Android OpenGL ES和OpenGL一起学(二)------理解Viewport(视口)和坐标系Android OpenGL ES篇(转帖)
    CSOM中如何取到managed metadata类型字段的类型信息
    "Value does not fall within the expected range" with managed metadata fields
    GLFW_KEY_KP_ADD和GLFW_KEY_KP_SUBTRACT
    OPENGL: WHY IS YOUR CODE PRODUCING A BLACK WINDOW?
    (转)真正的中国天气api接口xml,json(求加精) ...
    Mongo如何在多个字段中查询某个关键字?
    VS2010整合NUnit进行单元测试
    ASP.NET MVC3 学习心得------路由机制
    MVC3中 ViewBag、ViewData和TempData的使用和区别
  • 原文地址:https://www.cnblogs.com/Just--Do--It/p/7307902.html
Copyright © 2011-2022 走看看