2016暑期LNOI夏令营 T2解题报告

题面:


算法流程:

      首先我们需要求出最短路图,然后再图上进行记忆化搜索,然后边搜索边判断是否存在-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;
}

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值