矩阵类 poj3420

来源:互联网 发布:兼职淘宝扫二维码骗局 编辑:程序博客网 时间:2024/04/28 12:03
第一次写博客,希望以后能有个美好的回忆。。
决心把 算法与实现的题 都做一遍,加油!
这题我这个菜鸟整整研究了一个晚上才弄明白。。。好弱啊。。
已知第i行的状态,推导出第i+1行的可行性状态,状态用0,1,表示,同一行2个0表示一个横着的骨牌,同一列1个1表示竖着的骨牌
比如 第i行为 0000,(用数字1,2,3,4表示骨牌)
那么第i+1行的状态可以为 0000 即
1122
3344
也可以为0011,即
1134
2234
也可以为1111,即
1234
1234



用数组t[i][j]表示i和j是否是可行性状态,比如
i行:  0100
i+1行: 1011
那么t[4][11]=1
这样计算出状态方程t
计算方法为 保证i和j二进制的每一位最多有一个1,并且i^j=0000||0011||1001||1100||1111
计算完t后,利用矩阵快速幂计算a=t^n,最后a[0][0]就是答案


至于为什么a[0][0]是答案,我感觉a[i][j]表示的以i为第一行j为最后一行的所有可能情况
当n=1是不用说了
当n=2是所有的情况都可以写成以0000为第一行的形式即
  0000 0000 0000 0000 0000
  0000 0011 1001 1100 1111
即1122 1134 1224 1233 1234
  3344 2234 1334 1244 1234
五种情况
当n=3时


可以都可以写成 
  0000 0000 0000 0000 0000
  0000 0011 1001 1100 1111
  0000 0000 0000 0000 0000
即11种情况
所以以后无论n为奇数偶数都可由n=2和n=3的情况组合而成
而a[0][0]表示以0000开头 以0000结尾的情况 符合要求 
所以a[0][0]就是答案


不知道对不对,求大牛指点


# include <stdio.h># include <string.h>const int maxn=16;int t[maxn][maxn];int a[maxn][maxn],b[maxn][maxn];int dz[16];int mod;void mul(int d[maxn][maxn],int e[maxn][maxn],int f[maxn][maxn]){    int temp[maxn][maxn];    for(int i=0; i<maxn; i++)    {        for(int j=0; j<maxn; j++)        {            temp[i][j]=0;            for(int k=0; k<maxn; k++)            {                temp[i][j]=(temp[i][j]+d[i][k]*e[k][j])%mod;            }        }    }    for(int i=0; i<maxn; i++)    for(int j=0; j<maxn; j++)    f[i][j]=temp[i][j];}void pow(int n){    for(int i=0; i<maxn; i++)    for(int j=0; j<maxn; j++)    a[i][j]=t[i][j];    memset(b,0,sizeof(b));    for(int i=0; i<maxn; i++)    b[i][i]=1;    while(n)    {        if(n&1) mul(b,a,b);        mul(a,a,a);        n>>=1;    }}void init(){    dz[0]=dz[3]=dz[9]=dz[12]=dz[15]=1;    for(int i=0; i<16; i++)    {        for(int j=0; j<16; j++)        {            int k;            for(k=0; k<4; k++){                if((i&(1<<k))&&(j&(1<<k))) break;            }            if(k==4&&dz[i^j]==1) t[i][j]=1;        }    }}int main (){    init();    int n;    while(scanf("%d%d",&n,&mod)!=EOF)    {        if(n==0&&mod==0) break;        pow(n);        //for(int i=0; i<16; i++){for(int j=0; j<16; j++) printf("%d ",b[i][j]); printf("\n");}        printf("%d\n",b[0][0]);    }}


0 0