二分矩阵

Poj 3233题意要求矩阵S=A+A^2+A^3+...+A^k mod m,可以用二分的方法
首先矩阵相乘用一次二分,然后求和再用一次二分,两次二分。
其中,矩阵相乘二分: A^2k=A^k*A^k,
A^(2k+1)=A^k*A^k*A.
求和二分: A+A^2+A...+A^(2k+1) = A+A^2+...+A^k+A^(k+1)+A^(k+1)*(A+A^2+...+A^k).
A+A^2+...+A^2k  = A+A^2+...+A^k+A^k*(A+A^2+...+A^k).

我的代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
int n,m,k;
struct DATA
{
int a[32][32];
};
DATA point;
DATA mul(DATA a,DATA b)
{
    int i,j,k;
    DATA c;
    memset(c.a,0,sizeof(c.a));
    for(i=0;i<n;i++)
    for(j=0;j<n;j++)
    {
        if(a.a[i][j])//在这里优化了一下,仔细研究下
        for(k=0;k<n;k++)
        {
            c.a[i][k]+=a.a[i][j]*b.a[j][k];
            c.a[i][k]=c.a[i][k]%m;
            }
 }
     return c;
}
DATA mu(DATA a,int y)
{
    int i,j;
    DATA c;
    memset(c.a,0,sizeof(c.a));
    for(i=0;i<n;i++)
    c.a[i][i]=1;
    while(y>0)
    {
        if(y&1)
        c=mul(c,a);
        a=mul(a,a);
        y>>=1;
    }
    return c;
}
DATA aad(DATA a,DATA b)
{
    int i,j;DATA c;
    for(i=0;i<n;i++)
    for(j=0;j<n;j++)
    {
        c.a[i][j]=a.a[i][j]+b.a[i][j];
        c.a[i][j]=c.a[i][j]%m;
    }
    return c;
}
DATA work(DATA a,int j)
{
    DATA bb,cc,dd;int i;
   if(j==1)
        return a;
        cc=work(a,j/2);
        if(j&1)
            {
            dd=mu(a,j/2+1);
            bb=mul(cc,dd);
            dd=aad(dd,bb);
            dd=aad(dd,cc);
            return dd;
            }
       else
       {
         dd=mu(a,j/2);
            bb=mul(cc,dd);
            bb=aad(cc,bb);
            return bb;
       }
}
int main()
{int i,j,t;
    scanf("%d%d%d",&n,&k,&m);
        for(i=0;i<n;i++)
        for(j=0;j<n;j++)
        scanf("%d",&point.a[i][j]);
        point=work(point,k);
        for(i=0;i<n;i++)
        for(j=0;j<n;j++)
        {if(j==n-1)
            printf("%d\n",point.a[i][j]%m);
            else
            printf("%d ",point.a[i][j]%m);
            }
return 0;
}

你可能感兴趣的:(二分矩阵)