您的位置:首页 > 其它

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

2015-05-20 11:27 281 查看
题目大意:

有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
[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj dp 矩阵