//做完这题以后终于理解白书上的边为什么要那样定义了 可以很方便的在o(1) 时间内找到反向边
解法:先跑一边最短路,然后检查最短路上有没有0权边(dfs就好,但是每条边只能走一次,这里就需要用异或找反向边),最后记忆化搜索一遍(每条边也是只能走一次)
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<stack> 11 #include<string> 12 13 using namespace std; 14 15 const int INF=1000000000; 16 const int MOD=1000000009; 17 18 struct Edge{ 19 int from,to,cost; 20 }; 21 22 vector <Edge> edges; 23 vector <int> G[2007]; 24 bool vis[4000007]; 25 int dis[2007]; 26 bool inq[2007]; 27 int f[2007]; 28 int n,m; 29 30 void AddEdge(int x,int y,int z){ 31 edges.push_back((Edge){x,y,z}); 32 edges.push_back((Edge){y,x,z}); 33 int sz=edges.size(); 34 G[x].push_back(sz-2); 35 G[y].push_back(sz-1); 36 } 37 38 void SPFA(){ 39 dis[1]=0; 40 memset(inq,0,sizeof(inq)); 41 queue<int>q; 42 q.push(1); 43 inq[1]=1; 44 while (!q.empty()){ 45 int now=q.front(); 46 int sz=G[now].size(); 47 q.pop(); 48 for (int i=0;i<sz;i++){ 49 Edge& e=edges[G[now][i]]; 50 if (dis[e.to]>dis[now]+e.cost){ 51 dis[e.to]=dis[now]+e.cost; 52 if (!inq[e.to]){ 53 q.push(e.to); 54 inq[e.to]=1; 55 } 56 } 57 } 58 inq[now]=0; 59 } 60 } 61 62 bool check(int now){ 63 if (now==1) return 1; 64 bool flag=1; 65 int sz=G[now].size(); 66 for (int i=0;i<sz;i++){ 67 Edge& e=edges[G[now][i]]; 68 if (!vis[G[now][i]] && dis[now]==dis[e.to]+e.cost){ 69 vis[G[now][i]]=1; 70 vis[G[now][i]^1]=1; 71 if (e.cost==0) flag=false; 72 if (!check(e.to)) flag=false; 73 } 74 } 75 return flag; 76 } 77 78 int work(int now){ 79 if (f[now]!=-1) return f[now]; 80 f[now]=0; 81 int sz=G[now].size(); 82 for (int i=0;i<sz;i++){ 83 Edge& e=edges[G[now][i]]; 84 if (!vis[G[now][i]] && dis[now]==dis[e.to]+e.cost){ 85 vis[G[now][i]]=1; 86 vis[G[now][i]^1]=1; 87 f[now]=(f[now]+work(e.to))%MOD; 88 } 89 } 90 return f[now]; 91 } 92 93 94 int main(){ 95 scanf("%d%d",&n,&m); 96 for (int i=1;i<=n;i++) dis[i]=INF; 97 for (int i=0;i<m;i++){ 98 int x,y,z; 99 scanf("%d%d%d",&x,&y,&z); 100 AddEdge(x,y,z); 101 } 102 SPFA(); 103 //printf("%d ",dis[n]); 104 memset(vis,0,sizeof(vis)); 105 if (!check(n)){ 106 printf("-1 "); 107 return 0; 108 } 109 memset(vis,0,sizeof(vis)); 110 memset(f,-1,sizeof(f)); 111 f[1]=1; 112 printf("%d ",work(n)); 113 return 0; 114 } 115 /* 116 4 4 117 1 2 1 118 1 3 1 119 2 4 2 120 3 4 2 121 122 4 4 123 1 2 0 124 1 3 1 125 2 4 99 126 3 4 99 127 */