1. 程式人生 > 實用技巧 >LVS 之 algorithm and NAT model

LVS 之 algorithm and NAT model

矩陣可以用二維陣列或者vector陣列來儲存,但是vector陣列的操作可能會有點慢,遇到TLE且矩陣大小比較固定的題目,及時轉換到二維陣列。至於快速冪的實現,與普通整數快速冪思想一樣。一個簡單例題POJ3734,用vector陣列實現

#include<stdio.h>
#include<vector>
using namespace std;
typedef vector<int> vec;
typedef vector<vec> mat;
typedef long long ll;
const int mod=10007;
mat mul(mat &A,mat &B){
    mat C(A.size(),vec(B[0].size()));
    for(int i=0;i<A.size();i++){
        for(int k=0;k<B.size();k++){
            for(int j=0;j<B[0].size();j++){
                C[i][j]=(C[i][j]+A[i][k]*B[k][j])%mod;
            }
        }
    }
    return C;
}
mat pow(mat A,int n){
    mat B(A.size(),vec(A.size()));
    for(int i=0;i<A.size();i++){
        B[i][i]=1;
    }
    while(n!=0){
        if(n%2==1) B=mul(B,A);
        A=mul(A,A);
        n/=2;
    }
    return B;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        mat A(3,vec(3));
        A[0][0]=2;A[0][1]=1;A[0][2]=0;
        A[1][0]=2;A[1][1]=2;A[1][2]=2;
        A[2][0]=0;A[2][1]=1;A[2][2]=2;
        A=pow(A,n);
        printf("%d\n",A[0][0]);
    }
    return 0;
}

搞清楚矩陣乘法的步驟,這一部分程式碼就比較容易。難點在於發現規律,以及將規律轉化為矩陣。對於普遍的遞推式,有矩陣形式:

若是遞推式中有常數項,對應地需要擴充套件矩陣:

POJ3735,對錶中元素執行一系列加減、清空、置換的操作,並重復多次,每一次指令可以用矩陣進行記錄,計算矩陣冪即可求解。但是這裡的A、T與不同矩陣不同,需要擴充套件,T有n+1個元素,第一個為1其他為0;A是(n+1)*(n+1)單位矩陣,根據操作進行變換

#include<stdio.h>
typedef long long ll;
const int N=105;
struct mat{
    ll a[N][N];
    
void init(){ for(int i=0;i<N;i++){ for(int j=0;j<N;j++){ a[i][j]=0; } } } }; int n,m,k; mat mul(mat A,mat B){ mat C; C.init(); for(int i=0;i<=n;i++){ for(int k=0;k<=n;k++){ if(A.a[i][k]){
for(int j=0;j<=n;j++){ C.a[i][j]+=A.a[i][k]*B.a[k][j]; } } } } return C; } mat pow(mat A,int x){ mat B; B.init(); for(int i=0;i<=n;i++){ B.a[i][i]=1; } while(x!=0){ if(x%2==1) B=mul(B,A); A=mul(A,A); x/=2; } return B; } int main(){ while(scanf("%d%d%d",&n,&m,&k)!=EOF){ if(n==0&&m==0&&k==0) break; mat A; A.init(); for(int i=0;i<=n;i++) A.a[i][i]=1; char s[5]; int a,b; while(k--){ scanf("%s%d",s,&a); if(s[0]=='g') A.a[0][a]++; else if(s[0]=='e'){ for(int i=0;i<=n;i++) A.a[i][a]=0; } else{ scanf("%d",&b); for(int i=0;i<=n;i++){ int t=A.a[i][a]; A.a[i][a]=A.a[i][b]; A.a[i][b]=t; } } } mat T; T.init(); T.a[0][0]=1; T=mul(T,pow(A,m)); for(int i=1;i<=n;i++){ printf("%lld ",T.a[0][i]); } printf("\n"); } return 0; }

POJ3233,矩陣冪下一種獨特的型別,求S=A+A2+A3+...+An

最後再記錄一道題,在圖中求長度為k的路徑總數。k=1時,鄰接矩陣就是最後的答案矩陣,遍歷矩陣求和即可。k>=1,最後的答案矩陣是鄰接矩陣的k次冪。