迷路 HYSBZ - 1297 dp 矩阵优化

题解

由于所求时间t过大不能采用直接递推的方式,使用矩阵快速幂来加快递推速度复杂度降低为O((n*10)^3logt)
d[code(i, j)]表示i秒前j节点的方案数,最多存储10秒,code为编码函数
定义转移矩阵tran,因为每次乘上转移矩阵要将当前时间后推1秒所以tran[code(i, j)][code(i + 1. j)]=1表示每个节点由当前时间转移到下一秒的时间,i表示时间j表示节点编号
对于题目所给边(i, j, c)表示从i节点走到j节点花费c秒,则tran[code(c-1, i)][code(0, j)]=1表示从c秒前转移到现在时刻,-1是因为每次乘上转移矩阵要后推一秒时间

AC代码

#include 
#include 
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 110;
const int MOD = 2009;

struct Matrix
{
	ll m[MAXN][MAXN];
	static const int N = 100; //阶数
	Matrix(int v = 0)
	{
		memset(m, 0, sizeof(m));
		if (v)
			for (int i = 0; i < N; i++)
				m[i][i] = v;
	}
	Matrix operator * (const Matrix &b)
	{
		Matrix t;
		for (int i = 0; i < N; i++)
			for (int j = 0; j < N; j++)
				for (int k = 0; k < N; k++)
					t.m[i][j] = (t.m[i][j] + m[i][k] * b.m[k][j]) % MOD;
		return t;
	}
	friend Matrix operator ^ (Matrix a, int n)
	{
		Matrix t(1);
		while (n)
		{
			if (n & 1)
				t = t * a;
			a = a * a;
			n >>= 1;
		}
		return t;
	}
}tran, a; //a[0][code(i, j)]表示i秒前j节点的方案数 最多存储10秒
int code(int t, int x) //编码t秒x节点
{
	return t * 10 + x;
}
int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	int n, t;
	cin >> n >> t;
	for (int i = 0; i < n; i++)
	{
		char c;
		for (int j = 0; j < n; j++)
		{
			scanf(" %c", &c);
			c -= '0';
			if (c)
				tran.m[code(c - 1, i)][code(0, j)] = 1; //c秒前的i转移到0现在时刻的j -1是因为转移后推1秒时间
		}
	}
	a.m[0][0] = 1; //起点为1
	for (int i = 0; i < 9; i++)
		for (int j = 0; j < n; j++)
			tran.m[code(i, j)][code(i + 1, j)] = 1; //每次转移 当前位置转移到1秒前的状态
	a = a * (tran ^ t);
	cout << a.m[0][n - 1] << endl;

	return 0;
}

你可能感兴趣的:(_动态规划_,矩阵优化)