矩陣類 poj3420

曾經最動心發表於2014-03-27
第一次寫部落格,希望以後能有個美好的回憶。。
決心把 演算法與實現的題 都做一遍,加油!
這題我這個菜鳥整整研究了一個晚上才弄明白。。。好弱啊。。
已知第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]);
    }

}


相關文章