POJ2411 状态压缩DP POJ - 3420

//#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
#define ll long long
ll dp[13][1<<12];
int path[500005][3];
int a,b;
int w;
void dfs(int now,int pre,int l)
{
    if(l>a) return;
    if(l==a) 
    {
        path[w][0]=pre;
        path[w++][1]=now;
        return;
    }
    dfs(now<<1,pre<<1|1,l+1);
    dfs(now<<1|1,pre<<1,l+1);
    dfs(now<<2|3,pre<<2|3,l+2);

}
int main()
{


        while(~scanf("%d%d",&a,&b))
        {   if(a==0&&b==0) return 0;
            if(a*b%2==1) 
            {
                printf("0\n");
                continue;
            }
            w=0;
            if(a>b) swap(a,b);
            dfs(0,0,0);
            memset(dp,0,sizeof(dp));
            dp[0][(1<<a)-1]=1;
            for(int i=0;i<b;i++)
            {
                for(int j=0;j<w;j++)
                {

                    dp[i+1][path[j][1]]+=dp[i][path[j][0]];
                }
            }
            printf("%lld\n",dp[b][(1<<a)-1]);


        }


        return 0; 
}

参考博客 :http://blog.csdn.net/u013480600/article/details/19569291

用二进制模拟每一行的情况和他前一行的情况,然后正在用dp 由第一行往下推

二进制表示每一行 方块有三种放的方式 横放 把两格全部标成 1 竖放上边标成 0 下边标成 1这样每一行都能用二进制表示

path 二维 一个存他本身 另一个存他前面那个 所以dp 时 就是dp[i+1][path[j][1]]+=dp[i][path[j][0]]; 下一行的方法+=上一行的方法数

 dp[0][(1<<a)-1]=1; 初始化为1 假设第 0行全部是1 这样不会对下一行产生影响

最后直接输出 最后一行全部是1 的dp值就行。。

poj 3420与上题相识 给一个4*n的方块 要你用 1*2的铺满

//#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
#define ll long long
int w;
int mod;
struct mat
{
    int ma[16][16];
}dat;
void dfs(int now,int pre,int l)
{
    if(l>4) return;
    if(l==4) 
    {
        dat.ma[pre][now]++;
        return;
    }
    dfs(now<<1,pre<<1|1,l+1);
    dfs(now<<1|1,pre<<1,l+1);
    dfs(now<<2|3,pre<<2|3,l+2);

}
mat mupl(mat a,mat b)
{
    mat c;
    memset(c.ma,0,sizeof(c.ma));
    for(int i=0;i<16;i++)
    {
        for(int j=0;j<16;j++)
        {
            for(int k=0;k<16;k++)
            c.ma[i][j]=(c.ma[i][j] + a.ma[i][k]*b.ma[k][j])%mod;

        }
    }
    return c;


}
mat poww(int n)
{

    mat e,a=dat;
    memset(e.ma,0,sizeof(e.ma));
    for(int i=0;i<16;++i)
    e.ma[i][i]=1;
    while(n)
    {
        if(n&1) e=mupl(a,e);
        n>>=1;
        a=mupl(a,a);


    } 
    return e;

}
int main()
{
        int n;
        memset(dat.ma,0,sizeof(dat.ma));
        dfs(0,0,0);
        while(~scanf("%d%d",&n,&mod))
        {
            if(!n&&!mod) return 0;
            if(mod==1) 
            {
                printf("0\n");
                continue;
            }
            if(n==1||n==0)
            {
                printf("1\n");
                continue;
            }
            mat ans=poww(n);
            printf("%d\n",ans.ma[15][15]);
        }


        return 0; 
} 

参考 http://blog.csdn.net/u013480600/article/details/19644847
由于该题是列固定为4,所以pre和now的值最多有16种,设A[pre][now]=1表示兼容对前行pre和后行now的二进制形式兼容有1种情况(该值不是1就是0)。则令B=A*A,则
B[2][3]=A[2][0]*A[0][3]
+A[2][1]*A[1][3]
+A[2][2]*A[2][3]
+A[2][3]*A[3][3]
即(A*A)[2][3]表示pre=2与now=3之间还间隔了一行,并且pre与now远程兼容有多少种方式。(pre与now的远程距离为1).由于目标矩阵有n行,行号从1到n,则我们假想目标矩阵的上面还有1行是第0行,并且二进制形式为全1序列。所以我们要求的是第0行和第n行距离为n-1的远程兼容有多少种方法。
即求得就是(A^n)[0][15]的值,该值还要对mod求余。

猜你喜欢

转载自blog.csdn.net/qq_37493070/article/details/79161690