洛谷 4159 bzoj 1297 [SCOI2009]迷路 题解

博客观赏效果更佳

先说一句,矩阵真是太强了,啥玩意都能干。这个题是真的牛逼,做完我仿佛都变成了一个矩阵。

题意简述

给定一个图, n < = 10 n<=10 ,用邻接矩阵给出,每条边的权值是 0 , 9 0,9 之间的整数( 1 , 9 1,9 表示边权, 0 0 表示不连通)。请你求出从 1 1 n n 走边权和为 t t 的路径数。

思路

拆点。每个点能联通的只有 9 9 种边权,所以拆成 9 9 个点,拆成的点之间大的往小的连边,建出来一个$ 9n\times 9n 的邻接矩阵。 把这个矩阵求快速幂得到 t 次方,位于 (1,n)$位置的就是答案了。

具体的思维过程

  1. 如果我们的图边权是 0 , 1 0,1 ,那么该如何做呢?
  2. 如何把我们的图转化成1. 中那个图呢?

step.1 只有0,1的问题

设矩阵 f i f_i 中的 ( x , y ) (x,y) 位置表示:从 x x y y 边权和为 i i 的情况数。那么 f 1 f_1 应该就等于初始给定的邻接矩阵。

转移方程:枚举中转点 m m f n ( x , y ) f_n(x,y) = f n 1 ( x , m ) × f 1 ( m , y ) f_{n-1}(x,m)\times f_1(m,y)

然后我们发现,这 t m tm 不就是 f n = f n 1 × f 1 f_n=f_{n-1}\times f_1 么(矩阵乘法)。如果还有一点数学基础(或者你没有,但是你对前缀和很熟悉),你会发现,这个式子很容易推出通项 f n = ( f 1 ) n f_n={(f_1)}^n

所以,在只有 0 , 1 0,1 的图中,我们只要把邻接矩阵看成一个数学上的矩阵,拿矩阵快速幂求一下 t t 次方即珂。然后位于 ( 1 , n ) (1,n) 位置的数就是从 1 1 n n 边权和为 t t 的方案数了。

step.2 转化

我们发现边权只有 10 10 种,其中联通的还只有 9 9 种,所以我们把每个点拆成 9 9 个点。设 p ( i , v ) p(i,v) 表示点 i i 拆出来的第 v v 个点。为了节省空间,我们令 v v 0 0 8 8 中的整数(虽然理论上它应该是 1 1 9 9 中的整数)。(看到 p ( i , v ) p(i,v) 珂别想歪了,我还少一个 x x 和一个 i i

然后我们还要转换边权。对于同一个 i i ,我们令 p ( i , v ) p(i,v) p ( i , v 1 ) p(i,v-1) 之间连一条权为 1 1 的边。对于 u , v u,v 之间一条边权为 w w 的边,那就只要从 p ( u , 0 ) p(u,0) p ( v , w 1 ) p(v,w-1) 之间连一条权为 1 1 的边即珂。我们发现,经过我们刚刚建的那些辅助边, p ( u , 0 ) p(u,0) p ( v , 0 ) p(v,0) 之间的间接距离就是 w w ,而且我们现在只用了权为 0 0 1 1 的边。(虽然我说的只有权为 1 1 的边,但是我没有加上去的边权就是 0 0 )。

然后现在我们的图由于拆点,就变成了只有 0 0 1 1 边权的边了。套用刚刚的方法即珂。

具体实现的注意事项

  1. 别忘了膜 2009 2009
  2. 拆点的转化公式: p ( i , v ) = v n + i p(i,v)=v*n+i ,所以空间复杂度 O ( 81 n ) O(81n)
  3. l o n g l o n g longlong

代码:

#include<bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
	#define int long long 
	#define mod 2009
	#define F(i,l,r) for(int i=l;i<=r;++i)
	#define D(i,r,l) for(int i=r;i>=l;--i)
	#define Fs(i,l,r,c) for(int i=l;i<=r;c)
	#define Ds(i,r,l,c) for(int i=r;i>=l;c)
	#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
	#define MEM(x,a) memset(x,a,sizeof(x))
	#define FK(x) MEM(x,0)
	class Matrix//square matrix
	{
	    #define N 112//changeable
	    private:
	        int a[N][N];
	    public:
	        //variable list
	        int n;//size
	        //initialization
	        Matrix()
	        {
	            memset(a,0,sizeof(a));
	            n=0;
	        }
	        Matrix(int _n)
	        {
	            memset(a,0,sizeof(a));
	            n=_n;
	        }
	        Matrix(int _n,int _x)
	        {_x%=mod;
	            n=_n;
	            for(int i=0;i<N;++i)
	            {
	                for(int j=0;j<N;++j)
	                {
	                    a[i][j]=_x;
	                }
	            }
	        }
	
	        //get value
	        int* operator[](int i)
	        {
	            return *(a+i);
	        }
	
	        //set value
	        void Set(int x)
	        {x%=mod;
	            for(int i=0;i<N;++i)
	            {
	                for(int j=0;j<N;++j)
	                {
	                    a[i][j]=x;
	                }
	            }
	        }
	        void Identity()
	        {
	            memset(a,0,sizeof(a));
	            for(int i=0;i<N;++i)
	            {
	                a[i][i]=1;
	            }
	        }
	        #undef N //112
	};
	Matrix operator*(Matrix x,Matrix y)
	{
	    Matrix ans(x.n,0);
	    int n=ans.n;
	    for(int i=1;i<=n;++i)
	    {
	        for(int j=1;j<=n;++j)
	        {
	            for(int k=1;k<=n;++k)
	            {
	                ans[i][j]+=x[i][k]*y[k][j];
	                ans[i][j]%=mod;
	            }
	        }
	    }
	    return ans;
	}
	Matrix operator^(Matrix x,int p)
	{
	    Matrix ans(x.n,1);
	    ans.Identity();
	    while(p)
	    {
	        if (p&1) ans=ans*x;
	        x=x*x,p>>=1;
	    }
	    return ans;
	}

	int n,t,a[112][112];
	void Input()
	{
		scanf("%lld%lld",&n,&t);
		F(i,1,n) F(j,1,n)
		{
			scanf("%1lld",&a[i][j]);
		}
	}

	Matrix f(91,0);
	int pos(int i,int v)
	{
		return v*n+i;
	}
	void Soviet()
	{
		F(i,1,n) 
		{
			F(j,1,8) f[pos(i,j)][pos(i,j-1)]=1;

			F(j,1,n)
			{
				int x=a[i][j];
				f[i][pos(j,x-1)]=1;
			}
		}

		f=f^t;
		printf("%lld\n",f[1][n]);
	}
	void IsMyWife()
	{
		Input();
		Soviet();
	}
	#undef int //long long 
}
int main()
{
	Flandre_Scarlet::IsMyWife();
	getchar();getchar();
	return 0;
}
发布了210 篇原创文章 · 获赞 8 · 访问量 9000

猜你喜欢

转载自blog.csdn.net/LightningUZ/article/details/103327237