矩陣乘法

前一陣子FYHXYY連講了兩週的矩陣乘法,不過單學一個矩乘頂多是在學模擬對吧,所以我們要知道這個算法怎麼應用,這裏的話主要講怎樣優化遞推。

首先,我們要知道怎樣操作矩乘,公式如下:

C[i,j]=a[i,k]*b[k,j]

前提是a的列數和b的行數一致。

而且我們還要知道,一切矩陣的0次方(即單位矩陣)是這個樣子的


衆所周知,一般來講不少遞推的遞推式是這樣的

F[i]=c[1]*f[i-1]+c[2]*f[i-2]++c[k]*f[i-k]+q

然後我們可以構造兩個矩陣來優化這一遞推式

A矩陣:

[c1,c2,c3,,ck-1,ck,q

 1 ,0 ,0,0,,0,0,0

 0 ,1 ,0,0,,0,0,0

 ………………

 0 ,0 ,0,0,,1,0,0

0 ,0 ,0 ,0,,0,0,1]

B矩陣

[fi-1

 fi-2

 fi-3

 ……

 f0

1]

然後A*B=

[fi

 fi-1

 fi-2

 ……

 f1

1]

當然如果想要推導第p項的話,我們可以得到這麼一條式子

Ap*B=

[fp

 fp-1

 fp-2

 ……

 fp-k

 1]

好了,然後我們來圍觀一下POJ的一道題3744

題目點擊

我們可以很輕易地知道踩在某一格子上的機率是這樣的

F[i]=p*f[i-1]+(1-p)*f[i-2]

然後再進行分段計算即可,分段的依據是地雷所在位置。

對於任何地雷所在位置i,跨過它的機率是f[i-1]*(1-p)

把這些機率相乘就得到結論

注意:

1.     f[1]=1,f[0]=0(任何一段都是一樣的)

2.     把地雷按其所在位置排序後要先進行特判,如果起點就是地雷,掛;如果連續兩格是地雷,掛

3.     注意每一段的起點的取值

好吧,上代碼……

type matrix=array[1..2,1..2]of extended;
     line=array[1..2]of extended;
var bas,a:matrix;
    res:line;
    ans:extended;
    n,i,j:longint;
    p,q:extended;
    mine:array[1..100]of longint;
procedure sort(l,r: longint);//把地雷位置排序(不要問我爲什麼開快排,我當時有點無聊)
var
i,j,x,y: longint;
begin
  i:=l;
  j:=r;
  x:=mine[(l+r) div 2];
  repeat
    while mine[i]<x do
    inc(i);
    while x<mine[j] do
    dec(j);
    if not(i>j) then
    begin
      y:=mine[i];
      mine[i]:=mine[j];
      mine[j]:=y;
      inc(i);
      j:=j-1;
    end;
  until i>j;
  if l<j then
  sort(l,j);
  if i<r then
  sort(i,r);
end;
function mul(a,b:matrix):matrix;//矩陣乘法
var t:matrix;i,j,k:longint;
begin
  for i:=1 to 2 do
    for j:=1 to 2 do
    begin
      t[i,j]:=0;
      for k:=1 to 2 do
      t[i,j]:=t[i,j]+a[i,k]*b[k,j];
    end;
  exit(t);
end;
function solve(a:line;b:matrix):line;//都是矩陣乘法,不過這裏操作的是隻有一列的矩陣
var t:line;i,j:longint;
begin
  fillchar(t,sizeof(t),0);
  for i:=1 to 2 do
    for j:=1 to 2 do
    t[j]:=t[j]+a[i]*b[i,j];
  exit(t);
end;
function calc(n:longint):extended;//分段計算過程
var res:matrix;a:line;
begin
  bas[1,1]:=p;
  bas[1,2]:=q;
  bas[2,1]:=1;
  bas[2,2]:=0;
  res[1,1]:=1;
  res[1,2]:=0;
  res[2,1]:=0;
  res[2,2]:=1;//任何矩陣的零次方都是單位矩陣
  a[1]:=0;
  a[2]:=1;//f[1]=1,f[0]=0
  dec(n);
  while n>0 do
  begin
    if n mod 2=1 then res:=mul(bas,res);
    n:=n shr 1;
    bas:=mul(bas,bas);
  end;
  a:=solve(a,res);//a=a*bas^n
  exit(a[1]*q);
end;
procedure main;
var last:longint;
begin
  for i:=1 to n do
  read(mine[i]);
  readln;
  sort(1,n);
  if mine[1]=1 then
  begin
    writeln('0.0000000');
    exit;
  end;
  for i:=2 to n do
  if mine[i]-mine[i-1]=1 then
  begin
    writeln('0.0000000');
    exit;
  end;
  ans:=1;
  last:=1;
  q:=1-p;
  for i:=1 to n do
  begin
    ans:=ans*calc(mine[i]-last+1);
    last:=mine[i]+1;
  end;
  writeln(ans:0:7);
end;
begin
  while not eof do
  begin
    readln(n,p); 
    main;
  end;
end.


發佈了35 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章