1. 程式人生 > >藍橋杯(演算法訓練)——K好數

藍橋杯(演算法訓練)——K好數

演算法描述

問題描述

如果一個自然數N的K進製表示中任意的相鄰的兩位都不是相鄰的數字,那麼我們就說這個數是K好數。求L位K進位制數中K好數的數目。例如K = 4,L = 2的時候,所有K好數為11、13、20、22、30、31、33 共7個。由於這個數目很大,請你輸出它對1000000007取模後的值。

輸入格式

輸入包含兩個正整數,K和L。

輸出格式

輸出一個整數,表示答案對1000000007取模後的值。

樣例輸入

4 2

樣例輸出

7

資料規模與約定

對於30%的資料,KL <= 106;

對於50%的資料,K <= 16, L <= 10;

對於100%的資料,1 <= K,L <= 100。

思考過程

ps:題目考點是動態規劃,但是我還沒有去查動態規劃的內容,在此先記錄一下自己的思考過程

首先以K=5,L=3為例
先畫了樹狀圖,將所有情況列出。
將第一位設為①,0①表示第1位上的0,以此類推。
列出後將樹狀圖的情況簡化如下(數值代表有幾種情況):
第三層:
0③ = 1;
1③ = 1;
2③ = 1;
3③ = 1;
4③ = 1;

第二層:
0② = 0③ + 2③ + 3③ + 4③;
1② = 1③ + 3③ + 4③;
2② = 0③ + 2③ + 4③;
3② = 0③ + 3③ + 4③;
4② = 0③ + 1③ + 2③ + 4③;

第一層:
0① = 0; 因為首位不可能為0
1① = 1② + 3② + 4②;
2① = 0② + 2② + 4②;
3① = 0② + 3② + 4②;
4① = 0② + 1② + 2② + 4②;

由此規律想到可以列一個k行l列的二維陣列,每一行的值就是靠上述規律得來的。
建立二維陣列後,首先把最後一列的數值填滿為1.
(以K=6, L=4為例)得到陣列
Ⅰ Ⅱ Ⅲ Ⅳ
① 0 0 0 1
② 0 0 0 1
③ 0 0 0 1
④ 0 0 0 1
⑤ 0 0 0 1
⑥ 0 0 0 1

然後倒著從Ⅲ列即倒數第二列開始按照規律填充陣列
如果是第①行的數,就需要除去第Ⅳ列第②行的數,
如果是第⑥行的數,就需要除去第Ⅳ列第⑤行的數,
剩下的行數需要除去第Ⅳ列本行數減一和加一行的數。
將剩下的數相加,得到第Ⅲ列的數字如下
Ⅰ Ⅱ Ⅲ Ⅳ
① 0 0 5 1
② 0 0 4 1
③ 0 0 4 1
④ 0 0 4 1
⑤ 0 0 4 1
⑥ 0 0 5 1

按照上述規律,得到第Ⅱ列數和第Ⅰ列數後,陣列變為:
Ⅰ Ⅱ Ⅲ Ⅳ
① 97 22 5 1
② 74 17 4 1
③ 79 18 4 1
④ 79 18 4 1
⑤ 74 17 4 1
⑥ 97 22 5 1

最後,除去第①行第Ⅰ列的數字,因為首位數字不能為0,將其他第Ⅰ列的數字加和,就得到了所有的K好數的個數。
所以當K=6,L=4時,得到結果為74+79+79+74+97=403

注意事項

  • 掌握指標申請動態二維陣列的方法
  • 要注意求餘,否則會因數值大小超過限定長度而產生錯誤
  • 上述求餘時僅在最後求sum的值時求餘是不夠的,在陣列填充時就需要求餘了
  • 好好學數學啊我哭著,抽象模型出來太難了,這個題卡了我將近兩個小時,最開始一直在考慮排列組合但是總感覺不太對勁兒,後面想到用陣列表示也是靈機一動,最開始還想用算式列出來但是發現太不可行了,L=3還能勉強寫出來到了L=4的時候就徹底暈了。

程式碼表示

/*
    AUTHER:0_Re5et
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 100

int main()
{
    int k, l;
    int i, j;
    int Lcir, Hcir; 
    long int sum=0;
    long int **p;

    scanf("%d %d", &k, &l);

    p = (long int**)malloc(sizeof(long int*) * k);
    for(i=0; i<k; i++)
    {
        p[i] = (long int*)malloc(sizeof(long int) * l);
    } 
    // 申請二維陣列

    for(i=0; i<k; i++)
    {
        for(j=0; j<l; j++)
        {
            p[i][j]=0;
        }
    }
    // 陣列初始化 

    for(i=0; i<k; i++)
    {
        p[i][l-1] = 1;
    } 
    // 將最後一列的值設為1 

    for(Lcir=l-2; Lcir>=0; Lcir--)
    {
        // 列迴圈 

        for(Hcir=0; Hcir<k; Hcir++)
        {
            // 行迴圈


            if(Hcir == 0)
            {
                for(i=0; i<k; i++)
                {
                    if(i != 1)
                    {
                        p[0][Lcir] = p[0][Lcir] + p[i][Lcir+1];
                        p[0][Lcir] = p[0][Lcir] % 1000000007;
                    }
                    else
                        continue;
                }
            }
            else if(Hcir == k-1)
            {
                for(i=0; i<k; i++)
                {
                    if(i != k-2)
                    {
                        p[k-1][Lcir] = p[k-1][Lcir] + p[i][Lcir+1];
                        p[k-1][Lcir] = p[k-1][Lcir] % 1000000007;
                    }
                    else
                        continue;
                }
            }
            else
            {
                for(i=0; i<k; i++)
                {
                    if( (i != Hcir+1) && (i != Hcir-1) )
                    {
                        p[Hcir][Lcir] = p[Hcir][Lcir] + p[i][Lcir+1];
                        p[Hcir][Lcir] = p[Hcir][Lcir] % 1000000007;
                    }
                    else
                        continue;
                }
            }

        }
    }

    for(i=1; i<k; i++)
    {
        sum = sum + p[i][0];
        sum = sum % 1000000007;
    }
    printf("%ld", sum);

//  for(i=0; i<k; i++)
//  {
//      for(j=0; j<l; j++)
//      {
//          printf("%ld ", p[i][j]);
//      }
//      printf("\n");
//  }
    // 輸出陣列 


    return 0;
}