矩阵类的实现

2015/02/08 更新

       以这篇旧博客为基础,我将这个矩阵类改成了一个类模板,使用上应该会更方便一些。模板及例题见hdu5171 GTY's birthday gift(BC#29 1002)。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

博客原文

       例题:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2397

       感谢:haha1的代码,学了不少东西。为了方便以后自己使用,我把代码按自己的习惯稍作了修改。


       要点

  1. 可以在矩阵类中添加Zero、One、Two等几种特殊矩阵。比如此处Zero代表单位阵,One代表此题需要的一种特殊矩阵。
  2. Pow函数跟矩阵原值无关,所以第95行的代码res.Pow与res无关,只是使用了Zero、One。代码的命名方式res、step我可以借鉴学习,也按这个规范。
  3. 此题的答案本来是向量,但该作者仍用Matrix类存储,节约了许多代码(如果用一维数组存储,还要另写一类矩阵与向量的乘法)。而由此带来的运算复杂度增加是微不足道的。此处我按自己的逻辑习惯,将res原来的“行向量”改成“列向量”形式。虽然我发现把res写成行向量,在编程中可以直接使用*=的方便操作。
  4. 可以学习该作者map+vector的巧妙用法。
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;

typedef long long LL;
const int maxn = 75, MOD = 1000000009;

int n, N;
LL m;
map<LL, vector<LL> > s;

class Matrix {
public:
	LL val[maxn][maxn];
	Matrix() {
		memset(val, 0, sizeof(val));
	}

	Matrix operator*(const Matrix& c) const {
		Matrix res;
		for (int i = 0; i < n; ++i)
			for (int j = 0; j < n; ++j)
				for (int k = 0; k < n; ++k) {
					res.val[i][j] += val[i][k] * c.val[k][j];
					res.val[i][j] = (res.val[i][j] + MOD) % MOD; //防止矩阵元素变为负数,若不需要,去掉"+MOD"
				}
		return res;
	}

	Matrix& operator*=(const Matrix& c) {
		*this = *this * c;
		return *this;
	}

	Matrix Pow(LL k) { //返回one^k
		Matrix res = Zero();
		Matrix step = One();
		while (k) {
			if (k & 1)
				res *= step;
			k >>= 1;
			step *= step;
		}
		return res;
	}

	Matrix Zero() const {
		Matrix res;
		for (int i = 0; i < maxn; ++i)
			res.val[i][i] = 1;
		return res;
	}

	Matrix One() const {
		Matrix res;
		res.val[0][0] = res.val[0][1] = 1;
		res.val[n-1][n-1] = res.val[n-1][n-2] = 1;
		for (int i = 1; i < n - 1; ++i) {
			res.val[i][i-1] = res.val[i][i] = res.val[i][i + 1] = 1;
		}
		return res;
	}
};

int main() {
	int kcase = 0;
	while (scanf("%d%lld%d", &n, &m, &N) && n) {
		s.clear();
		for (int i = 0; i < N; ++i) {
			LL x, y;
			scanf("%lld%lld", &x, &y);
			s[--y].push_back(--x);
		}
		if (n == 1) {
			if (N) {
				printf("Case %d: 0\n", ++kcase);
			} else {
				printf("Case %d: 1\n", ++kcase);
			}
			continue;
		}
		Matrix res;
		res.val[0][0] = 1;
		LL now = 0;
		for (map<LL, vector<LL> >::iterator it = s.begin(); it != s.end(); ++it) {
			if (it -> first == 0) continue;
			res = res.Pow((it -> first) - now)*res;
			now = it -> first;
			for (int i = 0; i < (it -> second).size(); ++i) {
				res.val[(it -> second)[i]][0] = 0;
			}
		}
		res = res.Pow(m - 1 - now)*res;
		printf("Case %d: %lld\n", ++kcase, res.val[n-1][0]);
	}
    return 0;
}

你可能感兴趣的:(ACM,cc++,矩阵乘法快速幂模,矩阵类)