zoj3408 Gao 最短路 + DP

Gao

ZOJ Monthly, October 2010

好不容易看到一道图论,可惜没搞定。。

点数很多,N = 10000,很明显不能暴搜,单源最短路径,dijkstra我都没敢写,O(n^2),怕超时,记得有个O(nlog(n))的heap优化,还没学会,赛后看了解题报告,就是个最短路问题,只不过加了个DP过程,设s[v]表示源点到点v的路径数,t[v]表示点v到其余各点的路径数,则经过点v的最短路径总数就可以表示成s[v] * t[v],s[v]和t[v]都可以用DP的思想求的,s[v]要按照拓扑序DP,t[v]则按照反拓扑序DP。

我的SPFA写比较烂,跑了1000多ms。。

我发现C++里有个fill(a, a + n, key)函数,可以把a数组赋值为key,挺好用的。。。

 

代码
   
     
1 #include < iostream >
2 #include < cstdio >
3 #include < string .h >
4 #include < stdlib.h >
5 #include < algorithm >
6   #define MM 50004
7   #define NN 10004
8 #define LL long long
9 #define INF 0x3fffffff
10 #define MOD 10000000000LL
11
12 using namespace std;
13 typedef struct node{
14 int v, wt;
15 struct node * nxt;
16 }NODE;
17
18 NODE edg[MM];
19 NODE * Link[NN];
20 int idx;
21 int N, M, Q;
22 int stack[NN];
23 int mark[NN];
24 int dis[NN];
25 int ord[NN];
26 LL s[NN];
27 LL t[NN];
28
29 int cmp( const void * a, const void * b){
30 return dis[ * ( int * )a] - dis[ * ( int * )b];
31 }
32
33 void Add( int u, int v, int wt){
34 idx ++ ;
35 edg[idx].v = v;
36 edg[idx].wt = wt;
37 edg[idx].nxt = Link[u];
38 Link[u] = edg + idx;
39 }
40
41 void Spfa(){
42 int i, top, u, v, wt;
43 top = 0 ;
44 for (i = 0 ; i < N; i ++ ){
45 stack[ ++ top] = i;
46 mark[i] = 1 ;
47 dis[i] = INF;
48 }
49 dis[ 0 ] = 0 ;
50 while (top){
51 u = stack[top -- ];
52 mark[u] = 0 ;
53 for (NODE * p = Link[u]; p; p = p -> nxt){
54 v = p -> v;
55 wt = p -> wt;
56 if (dis[v] > dis[u] + wt){
57 dis[v] = dis[u] + wt;
58 if ( ! mark[v]){
59 mark[v] = 1 ;
60 stack[ ++ top] = v;
61 }
62 }
63 }
64 }
65 }
66
67 LL mul(LL lhs, LL rhs){ // 布斯乘法
68 LL sq = 100000 ;
69 LL lhs1 = lhs % sq;
70 LL rhs1 = rhs % sq;
71
72 return ((lhs / sq * rhs1 + rhs / sq * lhs1) * sq + lhs1 * rhs1) % MOD;
73 }
74
75 void Solve(){
76 Spfa();
77 int i, u;
78 for (i = 0 ; i < N; i ++ ){
79 ord[i] = i;
80 }
81 qsort(ord, N, sizeof ( int ), cmp);
82 fill(s, s + N, 0 );
83 s[ 0 ] = 1 ;
84 for (u = 0 ; u < N; u ++ ){
85 for (NODE * p = Link[ord[u]]; p; p = p -> nxt){
86 if (dis[p -> v] == dis[ord[u]] + p -> wt){
87 s[p -> v] = (s[p -> v] + s[ord[u]]) % MOD;
88 }
89 }
90 }
91 fill(t, t + N, 1 );
92 for (u = N - 1 ; u >= 0 ; u -- ){
93 for (NODE * p = Link[ord[u]]; p; p = p -> nxt){
94 if (dis[p -> v] == dis[ord[u]] + p -> wt){
95 t[ord[u]] = (t[ord[u]] + t[p -> v]) % MOD;
96 }
97 }
98 }
99 int a;
100 while (Q -- ){
101 scanf( " %d " , & a);
102 printf( " %010lld\n " , mul(s[a], t[a]));
103 }
104 }
105 int main()
106 {
107 int a, b, d;
108 while (scanf( " %d%d%d " , & N, & M, & Q) != EOF){
109 idx = 0 ; memset(Link, 0 , sizeof (Link));
110 while (M -- ){
111 scanf( " %d%d%d " , & a, & b, & d);
112 Add(a, b, d);
113 }
114 Solve();
115 }
116 return 0 ;
117 }
118

 

你可能感兴趣的:(最短路)