都说是经典题
http://http://acm.hdu.edu.cn/showproblem.php?pid=2254
解题思路:
城市最多有30个,然而p1,p2最大确实2^32,一般情况下,要开数组p[ 2^32 ][ 2^32 ]来存p1,p2之间的路径,这不太科学,所以应该用map稍稍处理一下,将数组开在30以内。
p[ 0 ].a[ i ][ j ]表示的是从i到j的路径数,我的理解就是这条路是否是通的,1表示有路,0表示没路,若cnt[ i ][ j ] = (p[ 0 ].a[ i ][ k ]*p[ 0 ].a[ k ][ j ])%mod(其中k=0~30),那么cnt就表示从i~j经过两条路一共有几种走法
那么最终的结果就是p[ 0 ].a ^(t1-1)+.......p[ 0 ].a^t2
t1,t2最多也就是10000,我们可以先打表,最后调用一下,缩短时间
#include <iostream>
#include <map>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
#define mod 2008
map<int,int>mp;
struct mat
{
int a[31][31];
};
mat p[10005];
mat mul(mat a,mat b,int n)
{
mat ret;
memset(ret.a,0,sizeof(ret.a));
for(int i=0;i<n;i++)
for(int k=0;k<n;k++)
if(a.a[i][k])
for(int j=0;j<n;j++)
if(b.a[k][j])
ret.a[i][j] = (ret.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
return ret;
}
int main()
{
int n,m;
while(cin>>n)
{
mp.clear();
int u,v;
int ans=0;
memset(p[0].a,0,sizeof(p[0].a));
while(n--)
{
cin>>u>>v;
if(mp.find(u) == mp.end()) mp[u]=ans++;
if(mp.find(v) == mp.end()) mp[v]=ans++;
p[0].a[mp[u]][mp[v]]++;
}
for(int i=1;i<10001;i++)
{
p[i] = mul(p[i-1],p[0],ans);
}
cin>>m;
int v1,v2,t1,t2;
while(m--)
{
cin>>v1>>v2>>t1>>t2;
if(mp.find(v1)==mp.end()||mp.find(v2)==mp.end()||(t1==0 && t2==0))
{
cout<<"0"<<endl;
continue;
}
int sum=0;
if(t1>t2)//一开始这里没写,wa了,题目并没有说t1,t2的大小,所以要考虑周全
{
int c=t1;
t1=t2,t2=c;
}
for(int i=t1-1;i<t2;i++)
{
if(i==-1) continue;//这里有wa了一把,p[-1]并不存在
sum=(sum+p[i].a[mp[v1]][mp[v2]])%mod;
}
cout<<sum<<endl;
}
}
return 0;
}
本文提供了一种解决HDU 2254问题的有效方法,通过使用map来优化存储结构,避免了传统的大规模数组开销,并通过矩阵乘法和预处理技术实现了快速求解。
1225

被折叠的 条评论
为什么被折叠?



