poj 2411 && 2663 && 3420 && 点头1033

来源:互联网 发布:淘宝假太岁什么做的 编辑:程序博客网 时间:2024/06/02 17:54


poj 2411 http://poj.org/problem?id=2411        

题意:让你用1*2的矩阵去填满n*m的方格,有多少种方法

题解:http://blog.csdn.net/shiwei408/article/details/8821853  

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;#define M 1<<11+1LL dp[14][M];int st[M*11][2];int n,m,cnt;void dfs(int cur,int now,int pre){    if(cur > m) return ;    if(cur == m){        st[cnt][0] = pre;        st[cnt][1] = now;        cnt ++;        return ;    }    dfs(cur + 2,((now<<2)|3),((pre<<2)|3));//当前行横放为11,那么上一行填11    dfs(cur + 1,((now<<1)|1),(pre<<1));// 当前行竖放为1,那么上一行填0    dfs(cur + 1,(now<<1),((pre<<1)|1));// 如果上一行为1,那么当前行不放置为0}int main(){    while(scanf("%d%d",&n,&m) , n + m){       if(n < m) swap(n,m);        cnt = 0;        memset(st,0,sizeof(st));        dfs(0,0,0);        memset(dp,0,sizeof(dp));        dp[0][(1<<m)-1] = 1;        for(int i = 0;i < n;i++)            for(int j = 0;j < cnt;j++)                dp[i+1][st[j][1]] += dp[i][st[j][0]];        cout << dp[n][(1<<m)-1] << endl;    }}

poj  2663 解题方法与上题一样,题意 用1*2 的矩阵填充3*n的矩阵有多少种方法

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;#define M 100int dp[50][M];int st[M*11][2];int n,m,cnt;void dfs(int cur,int now,int pre){    if(cur > m) return ;    if(cur == m){        st[cnt][0] = pre;        st[cnt][1] = now;        cnt ++;        return ;    }    dfs(cur + 2,((now<<2)|3),((pre<<2)|3));//当前行横放为11,那么上一行填11    dfs(cur + 1,((now<<1)|1),(pre<<1));// 当前行竖放为1,那么上一行填0    dfs(cur + 1,(now<<1),((pre<<1)|1));// 如果上一行为1,那么当前行不放置为0}int main(){//    freopen("1.txt","w",stdout);    while(scanf("%d",&n)){        if(n < 0) break;//        if(!n) {cout << 0 << endl;continue;}        m = 3;        if(n < m) swap(n,m);        cnt = 0;        memset(st,0,sizeof(st));        dfs(0,0,0);        memset(dp,0,sizeof(dp));        dp[0][(1<<m)-1] = 1;        for(int i = 0;i < n;i++)            for(int j = 0;j < cnt;j++)                dp[i+1][st[j][1]] += dp[i][st[j][0]];        cout << dp[n][(1<<m)-1] << endl;    }}


poj - 3420 题意 用1*2 的矩阵填充4*n的矩阵有多少种方法(n比较大,用矩阵快速幂解决)

递推公式为 f(n) = f(n-1) + 5 * f(n-2) + f(n-3) - f(n-4)

构造矩阵     

   1        5         1          -1

   1        0          0          0

   0        1          0          0

   0         0         1          0

此题还有一种方法:http://blog.csdn.net/shiwei408/article/details/8821853  

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;LL mod;int n;struct Z{    LL m[4][4];};Z q = {    1,5,1,-1,    1,0,0,0,    0,1,0,0,    0,0,1,0};Z y = {    1,0,0,0,    0,1,0,0,    0,0,1,0,    0,0,0,1};Z operator * (Z a,Z b){    Z c;    memset(c.m,0,sizeof(c.m));    for(int i = 0;i < 4;i++)        for(int j = 0;j < 4;j++)            for(int k = 0;k < 4;k++)                c.m[i][j] = (c.m[i][j] + a.m[i][k] * b.m[k][j]) % mod;    return c;}Z Pow(int x){    Z ret,p;    ret = y,p = q;    while(x){        if(x&1) ret = p*ret ;        p = p * p;        x >>= 1;    }    return ret;}int main(){    int a[] = {1,1,5,11,36};    while(cin >> n >> mod,n+mod){        if(n < 5){cout << (a[n]%mod) << endl;continue;}        Z r = Pow(n - 4);        LL ans = (r.m[0][0]*36 + r.m[0][1] * 11 + r.m[0][2]*5 + r.m[0][3]) % mod;        ans = (ans + mod) % mod;        cout << ans << endl;    }}

点头1033 骨牌覆盖V2         (状态压缩+矩阵乘法)

题意:同上 2<=n <= 10^9 && 2 <= m <= 5;

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;const LL mod = 1000000007;#define M 1<<5+1LL st[M][M];int n,m,cnt;struct Z{    LL  m[32][32];    Z(){memset(m,0,sizeof(m));}    void init(){        for(int i = 0;i < cnt;i++) m[i][i] = 1;    }};void dfs(int cur,int now,int pre){    if(cur > m) return ;    if(cur == m){        st[pre][now] = 1;        return ;    }    dfs(cur + 2,((now<<2)|3),((pre<<2)|3));//当前行横放为11,那么上一行填11    dfs(cur + 1,((now<<1)|1),(pre<<1));// 当前行竖放为1,那么上一行填0    dfs(cur + 1,(now<<1),((pre<<1)|1));// 如果上一行为1,那么当前行不放置为0}Z operator * (Z a,Z b){    Z c;    for(int i = 0;i < cnt ;i++)        for(int k = 0;k < cnt ;k++)            if(a.m[i][k])                for(int j = 0;j < cnt ;j++)                    c.m[i][j] = (c.m[i][j] + a.m[i][k] * b.m[k][j]) % mod;    return c;}Z pow(int n,Z a){    Z ret ;ret.init();    while(n){        if(n&1) ret = ret * a;        a = a * a;        n >>= 1;    }    return ret;}int main(){    while(~scanf("%d%d",&n,&m)){        if(n < m) swap(n,m);        memset(st,0,sizeof(st));        dfs(0,0,0);        cnt = 1 << m;        Z s;        for(int i = 0;i < cnt;i++)            for(int j = 0;j < cnt;j++)                s.m[i][j] = st[i][j];        s = pow(n,s);        printf("%lld\n",s.m[cnt-1][cnt-1]);    }    return 0;}




0 0
原创粉丝点击