[BZOJ1297][SCOI2009]迷路(拆點+矩陣乘法)
阿新 • • 發佈:2019-01-05
題目描述
題解
由於矩陣的冪只能處理邊權為1的情況,又由於邊權最大隻到9,可以將一個點拆成9個點,分別表示路徑的分段長度。
比如說1->2,5
求矩陣的冪即可。
程式碼
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int Mod=2009;
const int max_n=15;
const int max_N=105;
struct hp{int a[max_N][max_N];}unit,A,ans;
char s[max_n];
int squ[max_n][max_n];
int n,t;
inline hp cheng(hp a,hp b)
{
hp ans;
memset(ans.a,0,sizeof(ans.a));
for (int i=1;i<=n*9;++i)
for (int j=1;j<=n*9;++j)
for (int k=1;k<=n*9;++k)
ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j])%Mod;
return ans;
}
inline hp matrix_fast_pow(hp a,int p)
{
hp ans=unit;
for (;p;p>>=1,a=cheng(a,a))
if (p&1)
ans=cheng(ans,a);
return ans;
}
int main()
{
scanf("%d%d\n",&n,&t);
for (int i=1;i<=n*9;++i) unit.a[i][i]=1;
for (int i=1;i<=n;++i)
{
gets(s);
for (int j=1;j<=n;++j)
squ[i][j]=s[j-1]-'0';
}
for (int i=1;i<=n;++i)
for (int j=2;j<=8;++j)
A.a[n+(i-1)*8+j-1][n+(i-1)*8+j]=1;
for (int i=1;i<=n;++i) A.a[i][n+(i-1)*8+1]=1;
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
if (squ[i][j])
{
if (squ[i][j]==1)
A.a[i][j]=1;
else
A.a[n+(i-1)*8+squ[i][j]-1][j]=1;
}
ans=matrix_fast_pow(A,t);
printf("%d\n",ans.a[1][n]);
}
總結
這個拆點的思想很厲害呀。要注意以後不同的思想要融會貫通,比如說拆點在網路流裡很常用,這裡用的也非常巧妙。