矩阵快速幂模板(重载矩阵乘法)

矩阵快速幂模板

 

转载自

https://blog.csdn.net/Acerkoo/article/details/80587854

 

1. 将矩阵乘法的'+'号变为max,乘号变为'+'号

C++代码如下:

const int maxn = 105;
typedef long long ll;
ll n, m;

struct node{ // m*m, m^n 矩阵快速幂模板
	ll f[maxn][maxn]; // m * m
	node(){
		memset(f, 0, sizeof(f));
	}

	node operator*(const node &p){
		node ans; // 结果矩阵
		for (int i = 1; i <= m; i++){
			for (int j = 1; j <= m; j++){
				for (int k = 1; k <= m; k++)
					ans.f[i][j] = max(ans.f[i][j], f[i][k] + p.f[k][j]);
			}
		}
		return ans;
	}

	node Pow_mod(int n) // mat^n
	{
		node ans;
		node p = (*this);
		while(n){
			if (n&1) ans = ans * p;
			p = p * p;
			n >>= 1;
		}
		return ans;
	}
};

 

2. 常规矩阵乘法

 

几个注意点:

1. 结果对MOD取模

2. 快速幂的乘法Pow_mod函数需要构造单位阵ans

 

C++代码如下:

typedef long long ll;
const int maxn = 105;
const int MOD = 10000;

int m, n;

struct node // m*m
{
	ll f[maxn][maxn];
	node(){
		memset(f, 0, sizeof(f));
	}

	node operator*(const node &x) const{
		node ans; // 结果矩阵
		for (int i = 1; i <= m; i++){
			for (int j = 1; j <= m; j++){
				for (int k = 1; k <= m; k++)
					ans.f[i][j] = (ans.f[i][j] + (f[i][k] % MOD) * (x.f[k][j] % MOD)) % MOD;
			}
		}
		return ans;
	}

	node Pow_mod(int k) // (m*m)^k
	{
		node ans;
		node p = (*this);
		for (int i = 1; i <= m; i++){
				ans.f[i][i] = 1;
		}
		while (k){
			if (k & 1) ans = ans * p;
			p = p * p;
			k >>= 1;
		}
		return ans;
	}
};

 

两道例题

1. POJ 3070(斐波那契求值) 

https://vjudge.net/problem/POJ-3070 

题意:求斐波那契呀第n项对10000取模的结果

 

方法:

求{{1, 1, },{1, 0}}矩阵的n次方(每次乘法对P取模),取右上角元素即可

 

C++代码如下:

#include 
#include 
#include 
#include 
using namespace std;

#define INF 0x3f3f3f3f
typedef long long ll;
const int maxn = 105;
const int MOD = 10000;

int m, n;

struct node // m*m
{
	ll f[maxn][maxn];
	node(){
		memset(f, 0, sizeof(f));
	}

	node operator*(const node &x) const{
		node ans;
		for (int i = 1; i <= m; i++){
			for (int j = 1; j <= m; j++){
				for (int k = 1; k <= m; k++)
					ans.f[i][j] = (ans.f[i][j] + (f[i][k] % MOD) * (x.f[k][j] % MOD)) % MOD;
			}
		}
		return ans;
	}

	node Pow_mod(int k) // (m*m)^k
	{
		node ans;
		node p = (*this);
		for (int i = 1; i <= m; i++){ // 构造单位阵
				ans.f[i][i] = 1;
		}
		while (k){
			if (k & 1) ans = ans * p;
			p = p * p;
			k >>= 1;
		}
		return ans;
	}
};

int main()
{
	while(scanf("%d", &n) != EOF && n != -1){
		m = 2;
		node mat;
		mat.f[1][1] = 1; mat.f[1][2] = 1;
		mat.f[2][1] = 1; mat.f[2][2] = 0;

		mat = mat.Pow_mod(n);
		// for (int i = 1; i <= m; i++){
		// 	for (int j = 1; j <= m; j++)
		// 		cout << mat.f[i][j] << endl;
		// }
		int ans = mat.f[1][2];
		cout << ans << endl;
	}
	return 0;
}

 

2.  最大好感度

https://nanti.jisuanke.com/t/A1795 

思路:

类似于弗洛伊德,求出所有可能情况再取最大值。

重载矩阵乘法,将其乘法('*')重载为max,将'+'重载为'*'

C++代码如下:

#include 
#include 
#include 
#include 
using namespace std;

#define INF 0x3f3f3f3f
typedef long long ll;
const int maxn = 105;
const int MOD = 10000;

int m, n;

struct node // m*m
{
	ll f[maxn][maxn];

	node(){
		memset(f, 0, sizeof(f));
	}

	node operator*(const node &x){
		node ans;
		for (int i = 1; i <= m; i++){
			for (int j = 1; j <= m; j++){
				for (int k = 1; k <= m; k++)
					ans.f[i][j] = max(ans.f[i][j], f[i][k] + x.f[k][j]);
			}
		}
		return ans;
	}

	node Pow_mod(int k) // (m*m)^k
	{
		node ans;
		node p = (*this);
		// for (int i = 1; i <= m; i++){
		// 		ans.f[i][i] = 1;
		// }
		while (k){
			if (k & 1) ans = ans * p;
			p = p * p;
			k >>= 1;
		}
		return ans;
	}
};

int main()
{
	while(scanf("%d%d", &n, &m) != EOF){
		node mat;
		for (int i = 1; i <= m; i++){
			for (int j = 1; j <= m; j++)
				scanf("%lld", &mat.f[i][j]);
		}

		mat = mat.Pow_mod(n - 1);
		ll ans = 0;
		for (int i = 1; i <= m; i++){
			for (int j = 1; j <= m; j++)
				ans = max(ans, mat.f[i][j]);
		}
		printf("%lld\n", ans);
	}
	return 0;
}

 

 

你可能感兴趣的:(计算机基础知识,computer,science,and,tech)