题目地址:HDU 2254
必须得吐槽一下。。这题的数据是又弱又坑。。样例不过都能AC。。还有。。居然还有重边。。WA了一晚上。。
吐槽完毕,言归正传。。
根据离散数学里面的可达矩阵的性质,我们知道一个有向图的邻接矩阵的前n次幂的和即为可达矩阵,那么要求[t1-t2]之内的路径的条数,因为题目说了t1 = 0的时候为0。那么假设邻接矩阵为A,那么要求的就是A^(t1-1)+A^(t1)+...+A^(t2-1),为什么是从t1-1开始呢,因为邻接矩阵本身代表走一步的结果。
然后再加上离散化就可以做了。
代码如下:
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
using namespace std;
#define LL __int64
const int mod=2008;
int n;
LL q[40];
struct matrix
{
int ma[32][32];
} mat[10002];
matrix Mult(matrix x, matrix y)
{
int i, j, k;
matrix tmp;
memset(tmp.ma,0,sizeof(tmp.ma));
for(i=0; i<n; i++)
{
for(k=0; k<n; k++)
{
for(j=0; j<n; j++)
{
tmp.ma[i][j]=(tmp.ma[i][j]+x.ma[i][k]*y.ma[k][j])%mod;
}
}
}
return tmp;
}
int find1(LL x)
{
int i;
for(i=0; i<n; i++)
{
if(q[i]==x)
{
return i;
}
}
return -1;
}
void Pow()
{
for(int i=1; i<=10001; i++)
{
mat[i]=Mult(mat[i-1],mat[0]);
}
}
int main()
{
int m, k, i, j, t1 ,t2, u, v;
LL v1, v2;
while(scanf("%d",&m)!=EOF)
{
memset(mat[0].ma,0,sizeof(mat[0].ma));
n=0;
while(m--)
{
scanf("%d%d",&u,&v);
int f1=find1(u);
if(f1<0)
{
q[n++]=u;
f1=n-1;
}
int f2=find1(v);
if(f2<0)
{
q[n++]=v;
f2=n-1;
}
mat[0].ma[f1][f2]++;
}
scanf("%d",&k);
Pow();
while(k--)
{
scanf("%I64d%I64d%d%d",&v1,&v2,&t1,&t2);
int f1=find1(v1);
int f2=find1(v2);
if(f1<0||f2<0)
{
puts("0");
continue ;
}
int ans=0;
for(i=t1-1; i<t2; i++)
{
if(i==-1) continue ;
ans+=mat[i].ma[f1][f2]%mod;
ans%=mod;
}
printf("%d\n",ans);
}
}
return 0;
}
原文地址:http://blog.csdn.net/scf0920/article/details/39558091