洛谷P1608路径统计
前言
关于本题,我由于被坑了一晚上...所以甚至发了个讨论版(点击查看)
由于SPFA多次入队的特殊性,导致需要一些特殊操作(本题类似P1144最短路计数,但那个题不进行spfa特殊操作能过)
更改一处:此处对上文进行更改,由于P1144边权都为1,所以不存在多次入队的情况,所以实际上没有问题,是我考虑不周!
本题坑点(做法):
- 去重边(读入时)
- dp数组每次清0,保证不会重复计算路径数(若用dijk,则没这个问题),不过这样只能保证dp[n]的正确性,其余的dp数组最后都为0了
- 只要dp数组被更改过就要入队
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=2005; 4 const int maxm=2e6+10; 5 const int mod =100003; 6 int head[maxm],dis[maxn],vis[maxn],dp[maxn]; 7 int cnt; 8 /* 9 #define pr pair<int,int> 10 #define mp make_pair 11 priority_queue<pr,vector<pr>,greater<pr> > q; 12 */ 13 int v[maxn][maxn]; 14 int n,m; 15 queue<int> q; 16 struct edge 17 { 18 int to,nxt,w; 19 }a[maxm]; 20 void add(int x,int y,int w) 21 { 22 a[++cnt].nxt=head[x]; 23 head[x]=cnt; 24 a[cnt].to=y; 25 a[cnt].w=w; 26 } 27 bool flag; 28 void SPFA() 29 { 30 memset(dis,0x3f,sizeof(dis)); 31 // memset(vis,0,sizeof(vis));//注意清空 32 // for(int i=1;i<=n;i++) 33 // dis[i]=0x7fffffff; 34 dis[1]=0; 35 dp[1]=1; 36 vis[1]=1; 37 q.push(1); 38 while(!q.empty()) 39 { 40 int u = q.front(); 41 q.pop(); 42 vis[u]=0; 43 if(u==n) {flag=1;continue;} 44 for(int i=head[u];i;i=a[i].nxt) 45 { 46 int v=a[i].to; 47 if(dis[v]>dis[u]+a[i].w) 48 { 49 dis[v]=dis[u]+a[i].w; 50 dp[v]=dp[u]; 51 // if(!vis[v]) {q.push(v);vis[v]=1;} 52 } 53 else if(dis[v]==dis[u]+a[i].w) 54 { 55 dp[v]+=dp[u]; 56 } 57 if(dp[v]&&!vis[v]) {q.push(v);vis[v]=1;} 58 } 59 dp[u]=0; 60 } 61 } 62 int main() 63 { 64 scanf("%d%d",&n,&m); 65 int x,y,w; 66 for(int i=1;i<=m;i++) 67 { 68 scanf("%d%d%d",&x,&y,&w); 69 if(v[x][y]==0) 70 { 71 add(x,y,w); 72 v[x][y]=w; 73 74 } 75 else if(v[x][y]>w) 76 { 77 int j; 78 for (j=head[x];j&&a[j].to!=y;j=a[j].nxt) ; 79 a[j].w=w; 80 v[x][y]=w; 81 } 82 83 } 84 SPFA(); 85 if(!flag) printf("No answer"); 86 else 87 { 88 printf("%d %d\n",dis[n],dp[n]); 89 } 90 // for(int i=1;i<=n;i++) 91 // printf("%d ",dp[i]); 92 /* 93 5 5 94 1 2 1 95 2 3 1 96 3 4 1 97 4 5 1 98 1 4 3 99 输出:4 2 100 */ 101 return 0; 102 }
吐槽
关于SPFA:它死了!