noip2017 考了这个
不过比这个不知道高到哪里去了
但是毕竟可以用这个混到30分的呀.....
做法
大致有两种做法,可以spfa,也可以写dijkstra
重要的地方都差不多,即用一个数组cnt[ i ] 表示 dis[ i ]有多少种走法
实现
dijkstra很好想,每次都是走的最短路直接更新即可
spfa因为可能会反复进队,所以直接累加会导致重复计算。
很美妙的做法是 每次出队就把 cnt[ k ] 赋成0
题目可以做一下 luogu 1608
代码
dijkstra:
#include <bits/stdc++.h>
using namespace std;
#define maxn 2010
#define inf 1e9
int mp[maxn][maxn],dis[maxn],n,m,c[maxn],cnt,p[maxn];
int read(int x=0){scanf("%d",&x);return x;}
bool vis[maxn];
struct node{
int a,b,w,nt;
}e[maxn*maxn*2];
inline void add(int x,int y,int z){
e[++cnt].a=x,e[cnt].b=y,e[cnt].w=z;
e[cnt].nt=p[x];p[x]=cnt;
}
inline void dijkstra(){
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q;
for(int i=1;i<=n;i++)dis[i]=inf;
dis[1]=0;c[1]=1;
q.push(make_pair(dis[1],1));
while(!q.empty()){
pair<int,int> node=q.top();q.pop();
int k=node.second;
if(vis[k])continue;vis[k]=true;
for(int i=p[k];i;i=e[i].nt){
int kk=e[i].b;
if(dis[kk]==dis[k]+e[i].w)
c[kk]+=c[k];
else if(dis[kk]>dis[k]+e[i].w)
c[kk]=c[k],dis[kk]=dis[k]+e[i].w,q.push(make_pair(dis[kk],kk));
}
}
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)mp[i][j]=-1;
for(int i=1;i<=m;i++){
int a=read(),b=read(),c=read();
mp[a][b]=mp[a][b]==-1?c:min(c,mp[a][b]);
}
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
if(mp[i][j]!=-1)add(i,j,mp[i][j]);
dijkstra();
if(dis[n]==inf)puts("No answer");
else printf("%d %d",dis[n],c[n]);
return 0;
}
spfa:
#include <bits/stdc++.h>
using namespace std;
#define maxn 2010
#define inf 1e9
int mp[maxn][maxn],dis[maxn],n,m,c[maxn];
int read(int x=0){scanf("%d",&x);return x;}
bool vis[maxn];
inline void spfa(){
queue<int>q;
for(int i=1;i<=n;i++)dis[i]=inf;
dis[1]=0;c[1]=1;q.push(1);
while(!q.empty()){
int k=q.front();q.pop();vis[k]=false;
if(k==n)continue;
for(int kk=1;kk<=n;kk++)if(mp[k][kk]!=-1){
if(dis[kk]==dis[k]+mp[k][kk])c[kk]+=c[k];
if(dis[kk]>dis[k]+mp[k][kk])
dis[kk]=dis[k]+mp[k][kk],c[kk]=c[k];
if(c[kk]&&!vis[kk])vis[kk]=true,q.push(kk);
}
c[k]=0;
}
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)mp[i][j]=-1;
for(int i=1;i<=m;i++){
int a=read(),b=read(),z=read();
mp[a][b]=mp[a][b]==-1?z:min(mp[a][b],z);
}
spfa();
if(c[n]==0)puts("No answer");
else printf("%d %d",dis[n],c[n]);
return 0;
}