poj 3734 Blocks (矩阵快速幂优化的动态规划)

来源:互联网 发布:redis数据库有什么用 编辑:程序博客网 时间:2024/05/16 08:07

题目大意:

有4种颜色,去涂满n个格子,其中要求红和绿两种颜色涂偶数次。问:最终有多少种不同的填涂方案。

解题思路:

一开始以为是排列组合,但是n的范围太大。

可以很明显的得到一个dp方程:dp[i][j][k] 表示涂第i 位,红色是否为偶数,绿色是否为偶数,值表示种数。

dp[i][0][0] = dp[i-1][0][0]*2+dp[i-1][0][1]*1+dp[i-1][1][0]*1+dp[i-1][1][1]*0,其他的同理。最后只要输出dp[n][0][0]就可以了。

一开始,我初始化 dp[1][0][0] = 2 出错了。然后想到 一个都不涂的时候,也算一种填涂方案。所以把dp初始化为dp[0][0][0] = 1,其他为0就对了。

如果我们按照n一位一位的推导,由于n很大,所以肯定不行。


我们可以把推导式 通过矩阵的方式进行存储推导,那么就可以用矩阵快速幂的方式进行矩阵优化。


矩阵快速幂的运算,跟一般的快速幂一样,也是运用了二分的思想。单位矩阵相当于一般快速幂的数字 1 

具体代码如下:

在下面的代码中,dp用两维表示,而不是之前的三维,其中第一维意义不变,第二维   0 表示 红奇 绿奇 ; 1 表示 红奇 绿偶 ; 2 表示 红偶 绿奇; 3 表示 红偶 绿偶。

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<string>using namespace std;struct node//矩阵{    int a[5][5];    node()    {        memset(a,0,sizeof(a));    }};void setNodeI(node &x)//设置为单位矩阵{    for(int i = 0; i < 5; i++)    {        x.a[i][i]=1;    }}node mul(node x,node y,int n,int k,int m)//n行k列与k行m列的矩阵相乘{    node z;    for(int i=0; i<n; i++)    {        for(int j=0; j<m; j++)        {            for(int t=0; t<k; t++)            {                z.a[i][j] += (x.a[i][t])*(y.a[t][j]);            }            z.a[i][j]%= 10007;        }    }    return z;}node qmul(node x,int cnt)//矩阵快速幂{    node I;    setNodeI(I);    while(cnt>=1)    {        if(cnt%2) I = mul(I,x,4,4,4);        x = mul(x,x,4,4,4);        cnt = cnt>>1;    }    return I;}int main(){    node one;    node tem;    int n,m,i,j;    one.a[3][0]=1;//初始化dp    tem.a[0][0]=2;tem.a[0][1]=tem.a[0][2]=1;//初始化原始矩阵    tem.a[1][1]=2;tem.a[1][0]=tem.a[1][3]=1;    tem.a[2][2]=2;tem.a[2][0]=tem.a[2][3]=1;    tem.a[3][3]=2;tem.a[3][1]=tem.a[3][2]=1;    while(scanf("%d",&n)==1)    {        while(n--)        {            scanf("%d",&m);            node tmp = tem;            node ans = qmul(tmp,m);            ans = mul(ans,one,4,4,1);            printf("%d\n",ans.a[3][0]);        }    }    return 0;}


0 0
原创粉丝点击