矩陣乘法(四):分析問題,確定遞推式,採用矩陣快速冪求解

来源:https://www.cnblogs.com/cs-whut/archive/2019/09/04/11456718.html
-Advertisement-
Play Games

應用矩陣快速冪運算可以解決遞推問題。在實際應用中,有時候題目並沒有直接給出遞推式,需要認真分析問題,找出遞推式,然後再利用矩陣快速冪運算加快問題的求解。 【例1】程式閱讀理解。 有如下的C語言程式: #include <stdio.h>int main(){ int n,m,f,i; while(s ...


      應用矩陣快速冪運算可以解決遞推問題。在實際應用中,有時候題目並沒有直接給出遞推式,需要認真分析問題,找出遞推式,然後再利用矩陣快速冪運算加快問題的求解。

【例1】程式閱讀理解。

      有如下的C語言程式:

#include <stdio.h>
int main()
{
     int n,m,f,i;
     while(scanf("%d%d",&n,&m)!=EOF)
     {
           f=0;
           for(i=1;i<=n;i++)
           {
                if (i&1)f=(f*2+1)%m;
                else f=f*2%m;
           }
           printf("%d\n",f);
     }
     return 0;
}

       閱讀上面的程式,根據輸入的n和m,寫出程式運行的結果。例如,輸入 3  10,輸出應為5。

       但由於給定輸入的n和m的數據範圍為1<=n, m <= 1000000000,且測試集中數據量較大,因此如果直接將給定的程式提交會超時的。請你編寫一個程式,能根據輸入的n和m快速完成問題的求解,以實現給定程式的功能。

      (1)編程思路。

      給定程式段實際是通過迭代的方式求f(n)%m的值。先不考慮求餘,找到f(n)的求法。

      分析給定程式知,f(0)=0, 當 n為奇數時,f(n)=2*f(n-1)+1;當n為偶數時,f(n)=2*f(n-1)。

      下麵進一步分析,找到不考慮n的奇偶性的一個統一的遞推式。

       當 n為奇數時,f(n)=2*f(n-1)+1,n-1一定為偶數,f(n-1)=2*f(n-2)。因此,

                f(n)=f(n-1)+f(n-1)+1=2*f(n-2)+f(n-1)+1。

       當 n為偶數時,f(n)=2*f(n-1),n-1一定為奇數,f(n-1)=2*f(n-2)+1。因此,

                f(n)=f(n-1)+f(n-1)=2*f(n-2)+f(n-1)+1。

      由此,得到統一的遞推式: f(0)=0,f(1)=1,  f(n)=2*f(n-2)+f(n-1)+1  (n>=3)。

      確定了遞推式後,可以構造矩陣P,進行快速冪運算求解。

       

      

       

        (2)源程式。

#include <stdio.h>
#include <string.h>
struct Matrix
{
      __int64 mat[4][4]; // 存儲矩陣中各元素
};
Matrix matMul(Matrix a ,Matrix b,int n,int m)
{
      Matrix c;
      memset(c.mat,0,sizeof(c.mat));
      int i,j,k;
      for (k = 1; k<=n ; k++)
          for (i=1 ;i<=n ; i++)
              if (a.mat[i][k]!=0)
                  for (j = 1 ;j<=n ;j++)
                      c.mat[i][j] = (c.mat[i][j] + a.mat[i][k] * b.mat[k][j]) % m;
      return c;
}
Matrix quickMatPow(Matrix a ,int n,int b,int m) // n階矩陣a快速b次冪
{
      Matrix c;
      memset(c.mat ,0 ,sizeof(c.mat));
      int i;
      for (i = 1 ;i <= n ;i++)
           c.mat[i][i] = 1;
      while (b!=0)
      {
           if (b & 1)
               c = matMul(c ,a ,n,m); // c=c*a;
           a = matMul(a ,a ,n,m); // a=a*a
           b /= 2;
      }
      return c;
}
int main()
{
      int n,m;
      __int64 ans;
      Matrix p;
      while(scanf("%d%d" ,&n,&m)!=EOF)
      {
            memset(p.mat,0,sizeof(p.mat));
            p.mat[2][1]=2;
            p.mat[1][2]=p.mat[2][2]=1;
            p.mat[2][3]=p.mat[3][3]=1;
            if (n<3)
                 printf("%d\n",n%m);
           else
           {
                 p = quickMatPow(p,3,n-2,m);
                 ans=p.mat[2][1]% m;
                 ans=(ans+p.mat[2][2]*2)% m;
                 ans=(ans+p.mat[2][3])% m;
                 printf("%I64d\n" ,ans);
          }
      }
      return 0;
}

將此源程式提交給HDU 4990 “Reading comprehension”,可以Accepted。

【例2】將燈全熄滅。

       有n個燈排成一行,初始時是全亮的,第一個燈可以按(按下之後改變狀態)。然後如果前k個燈全熄滅且第k+1個燈亮,則第k+2個燈可以按。問至少要多少步滅掉所有燈?

      例如,n=2時,需要2歩。第1歩滅掉2號燈,第2歩滅掉1號燈。n=3時,需要5歩。第1歩滅掉1號燈,第2歩滅掉3號燈,第3歩點亮1號燈(註意1號燈不點亮,不能直接滅2號燈),第4歩滅掉2號燈,第5歩滅掉1號燈。

      (1)編程思路。 

       設f[n]代表n個全亮的燈變成全熄滅所需的最少步數,也可以代表n個全熄滅的燈變成全點亮所需的最少步數。 
      1)要想滅掉最後一個燈,得先滅掉前n-2個燈(第n-1個燈留亮),需要步數 f[n-2]+1。 
      2)要想滅掉第n-1個燈,得先讓第n-2個燈變回亮,要第n-2個燈變回亮,得先讓第n-3個燈變回亮...即要把前n-2個燈都變回亮,需要步數 f[n-2]。 
      3)把前n-2個燈變回亮後,就剩下前n-1個燈都是亮的,即剩下的任務就是把n-1個燈滅掉,需要步數 f[n-1]。 
      綜上所述:f[n] = 2*f[n-2] + f[n-1] + 1。 (n>=3)  f[1]=1,f[2]=2。

      (2)源程式。

#include <stdio.h>
#include <string.h>
#define MOD 200907
struct Matrix
{
       __int64 mat[4][4]; // 存儲矩陣中各元素
};
Matrix matMul(Matrix a ,Matrix b,int n)
{
      Matrix c;
      memset(c.mat,0,sizeof(c.mat));
      int i,j,k;
      for (k = 1; k<=n ; k++)
          for (i=1 ;i<=n ; i++)
              if (a.mat[i][k]!=0)
                  for (j = 1 ;j<=n ;j++)
                      c.mat[i][j] = (c.mat[i][j] + a.mat[i][k] * b.mat[k][j]) % MOD;
      return c;
}
Matrix quickMatPow(Matrix a ,int n,int b) // n階矩陣a快速b次冪
{
      Matrix c;
      memset(c.mat ,0 ,sizeof(c.mat));
      int i;
      for (i = 1 ;i <= n ;i++)
            c.mat[i][i] = 1;
      while (b!=0)
      {
           if (b & 1)
                c = matMul(c ,a ,n); // c=c*a;
           a = matMul(a ,a ,n); // a=a*a
           b /= 2;
      }
      return c;
}
int main()
{
      int n;
      __int64 ans;
      Matrix p;
      while(scanf("%d" ,&n) && n!=0)
      {
           memset(p.mat,0,sizeof(p.mat));
           p.mat[1][2]=2;
           p.mat[1][1]=p.mat[1][3]=1;
           p.mat[2][1]=p.mat[3][3]=1;
           if (n<3)
               printf("%d\n",n%MOD);
           else
           {
                p = quickMatPow(p,3,n-2);
                ans=(p.mat[1][1]*2+p.mat[1][2]+p.mat[1][3])%MOD;
                printf("%I64d\n" ,ans);
           }
      }
      return 0;
}

將此源程式提交給HDU 2842 “Chinese Rings”,可以Accepted。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 2019 年對於大前端技術領域而言變化不算太大,目前三大技術框架日趨成熟,短期內不大可能出現顛覆性的前端框架 (內心 OS:出了也學不動了)。本文結合個人和團隊經歷對 2019 上半年做個技術總結,將各類技術框架、語言、工具分作兩個維度,按照大前端技術架構圖進行分層,大體分為:狀態管理、UI 組件、... ...
  • jquery 實現只能選中一個checkbox,選中當前的去除上一個 ...
  • 1.qrious是基於canvas的純JS二維碼生成插件 1.1什麼是二維碼 二維碼又稱QR Code,QR全稱Quick Response,是一個近幾年來移動設備上超流行的一種編碼方式,它比傳統的Bar Code條形碼能存更多的信息,也能表示更多的數據類型。 二維條碼/二維碼(2-dimensio ...
  • 參照網上的一個案例“參照的為繪製的是一個動態的圓環”,現在我的需求是改編成四分之三的圓環實現效果: 樣式展示 canvas繪圖基本操作設置就可以參考源代碼鏈接:原文:https://blog.csdn.net/qq_21058391/article/details/76691047 > 引用的上文源 ...
  • 一、MongoDB資料庫 1、概念 資料庫(DataBase)是一個按照數據結構進行數據的組織,管理,存放數據的倉庫。 2、關係型資料庫 按照關係模型存儲的資料庫,數據與數據之間的關係非常密切,可以實現跨數據表查詢數據,占用更少的硬碟實現更多的數據存儲 T SQL標準的結構化查詢語言,是關係型資料庫 ...
  • 1.代碼生成器: [正反雙向](單表、主表、明細表、樹形表,快速開發利器)freemaker模版技術 ,0個代碼不用寫,生成完整的一個模塊,帶頁面、建表sql腳本、處理類、service等完整模塊2.多數據源:(支持同時連接無數個資料庫,可以不同的模塊連接不同數的據庫)支持N個數據源3.阿裡資料庫連 ...
  • Builder 模式定義 Builder 模式中文叫作建造者模式,又叫生成器模式,它屬於對象創建型模式,是將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。建造者模式是一步一步創建一個複雜的對象,它允許用戶只通過指定複雜對象的類型和內容就可以構建它們,用戶不需要知道內部的具體 ...
  • 前言 在開發十萬博客系統的的過程中,前面主要分享了爬蟲、緩存穿透以及文章閱讀量計數等等。爬蟲的目的就是解決十萬+問題;緩存穿透是為了保護後端資料庫查詢服務;計數服務解決了接近真實閱讀數以及資料庫服務的壓力。 架構圖 限流 就拿十萬博客來說,如果存在熱點文章,可能會有數十萬級別的併發用戶參與閱讀。如果 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...