上交 算法与实现 1.1.1 矩阵类 poj3420


决心把 算法与实现的题 都做一遍,加油!
这题我这个菜鸟整整研究了一个晚上才弄明白。。。好弱啊。。
已知第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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值