题面:
算法流程:
首先我们需要求出最短路图,然后再图上进行记忆化搜索,然后边搜索边判断是否存在-1的情况,最后输出即可。
那怎么求最短路图,最短路图的求法因题而定,本题是通过从1号店进行一遍dij,然后看每一条边,如果这条边的连个端点的dis值差 == 这条边的边权,那么其即为最短路图的一部分,构造新图即可,至于其正确性,显然嘛~
那我们再详细考虑一下-1的情况,什么情况下有无限条路径呢:1、通往终点的路上有一条边边权为0,那么无论在这条边上走多少遍,都是最短路径,所以有无限个。2、通往终点的最短路图上有一个点连出了一遍边权0的边,(注意此情况已经包括对结果有影响的自环),那么我们可以反复走这条边,仍不影响最短路,为无限条方案。
至于记忆化搜索,则搜一个点到终点的路径条数,这样子搜下去,一个点的返回值是其他连出点的和。
失误之处:
开始在本地评测的时候没有开栈,莫名的RE,这里说一下开栈的编译命令(-Wl,--stack=1048576000)
开始没有进行记忆化搜索,而是选择通过最短路图上的dis值排序来进行DP,然而会出现很多难以解决的问题,因为所求出的最短路图,依旧有很多边无法到达终点,所以这么DP的正确性是不对的。
记忆化搜索的时候,搜到n就会推出,然而可能从n号点连出一条0的边,那么也应输出-1
在进行搜索时,没有去考虑搜到边界返回前,是否还有什么需要处理的
数组压线开的,然而本人从1,开始就re一些点了
考试的时候,我用文件调试,但是没有注意到后缀隐藏,road.in 被搞成了 road.in.txt 导致我调试的天昏地暗也输出0,内心万念俱灰,整体影响了考试的心态与策略
体会心得:
自己在windows上都会出现系统操作的失误,那么noilinux更应该提前熟悉
如果搜索的时候还顺带着判断些什么东西,那么一定注意,我搜到终点要不要判断要判断的东西,还是直接返回就行。
数组开的大一些,有益身心健康
AC代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
using
namespace
std;
struct
lx
{
long
long
x,ly;
};
const
bool
operator < (
const
lx x,
const
lx y)
{
return
x.x > y.x;
}
const
long
long
mo = 1000000009;
priority_queue<lx> dl;
long
long
ans[300000],sum,cnt,x,y,z;
long
long
n,m,head[300000],nxt[500000],to[500000],wei[500000];
long
long
dis[500000],nhead[300000],nnxt[500000],nto[500000],nwei[500000];
bool
vis[300000],wx,nvis[300000];
void
cr(
long
long
x,
long
long
y,
long
long
w)
{
sum++;
nxt[sum] = head[x];
head[x] = sum;
to[sum] = y;
wei[sum] = w;
}
void
ncr(
long
long
x,
long
long
y,
long
long
w)
{
cnt++;
nnxt[cnt] = nhead[x];
nhead[x] = cnt;
nto[cnt] = y;
nwei[cnt] = w;
}
void
sread()
{
freopen
(
"road.in"
,
"r"
,stdin);
freopen
(
"road.out"
,
"w"
,stdout);
scanf
(
"%I64d%d"
,&n,&m);
for
(
long
long
i = 1;i <= m;i++)
{
scanf
(
"%I64d%d%d"
,&x,&y,&z);
cr(x,y,z);
cr(y,x,z);
}
}
lx make(
long
long
x,
long
long
ly)
{
lx tp;
tp.x = x;
tp.ly = ly;
return
tp;
}
void
dij()
{
dl.push(make(0,1));
for
(
long
long
i = 2;i <= n;i++)
dis[i] = 999999999999999;
while
(!dl.empty())
{
lx tp = dl.top();
dl.pop();
if
(vis[tp.ly])
continue
;
vis[tp.ly] =
true
;
for
(
long
long
i = head[tp.ly];i;i = nxt[i])
{
if
(dis[to[i]] > dis[tp.ly] + wei[i])
{
dis[to[i]] = dis[tp.ly] + wei[i];
if
(!vis[to[i]])
{
dl.push(make(dis[to[i]],to[i]));
}
}
}
}
}
void
mxt()
{
long
long
st = m * 2;
for
(
long
long
i = 1;i <= st;i++)
{
long
long
tp1 = to[i];
long
long
tp2 = 0;
if
(i & 1) tp2 = to[i + 1];
else
tp2 = to[i - 1];
if
(dis[tp1] - dis[tp2] == wei[i])
{
//printf("** %I64d %I64d dis2 %I64d dis1 %I64d %I64d\n",tp2,tp1,dis[tp2],dis[tp1],wei[i]);
ncr(tp2,tp1,wei[i]);
}
}
}
void
sinit()
{
dij();
mxt();
}
long
long
dfs(
long
long
x)
{
if
(x == n)
{
for
(
long
long
tp = head[x];tp;tp = nxt[tp])
{
if
(!wei[tp])
{
printf
(
"-1"
);
exit
(0);
}
}
}
if
(wx)
return
0;
if
(nvis[x])
return
ans[x];
nvis[x] =
true
;
long
long
tot = 0;
for
(
long
long
tp = nhead[x];tp;tp = nnxt[tp])
{
long
long
ftp = dfs(nto[tp]);
if
(ftp && !nwei[tp])
{
wx =
true
;
return
0;
}
tot += ftp;
long
long
ltp = tot;
ltp %= mo;
tot = ltp;
}
if
(tot)
{
for
(
long
long
tp = head[x];tp;tp = nxt[tp])
{
if
(!wei[tp])
{
printf
(
"-1"
);
exit
(0);
}
}
}
ans[x] = tot;
nvis[x] =
true
;
return
tot;
}
void
sprint()
{
nvis[n] =
true
;
ans[n] = 1;
long
long
stp =dfs(1) % mo;
if
(wx)
printf
(
"-1\n"
);
else
printf
(
"%I64d\n"
,stp);
}
int
main()
{
sread();
sinit();
sprint();
return
0;
}
|