Problem: Sightseeing
Description: 给你一个有向图。现在问你最短路的条数和比最短路长度大一的路径条数一共是多少。
Solution: 通过这个题目,熟悉了求解最短路和次短路的长度和条数的方法,真正理解了迪杰斯特拉。我们在用迪杰斯特拉更新
dis
的时候要判断小于最短路、等于最短路、小于次短路、等于次短路的情况。仔细画个图就理解了。看代码吧。哦,对了,这个题目是的起点是从1开始的,而我的代码是从0开始的。因此一开始错了很久。
Code(C++):
#include <stdio.h>
#include <string.h>
const int M=1005;
const int E=10005;
const int INF=0x3f3f3f3f;
typedef struct tagNode{
int from,to;
int c;
int next;
tagNode(){
}
tagNode(int from,int to,int c,int next){
this->from=from;
this->to=to;
this->c=c;
this->next=next;
}
}Node;
int n,m;
int src,des;
Node edge[E];
int head[M];
int dis[2][M];
int used[2][M];
int cnt[2][M];
int dij(int src)
{
memset(used,false,sizeof(used));
memset(cnt,0,sizeof(cnt));
memset(dis,INF,sizeof(dis));
dis[0][src]=0;
cnt[0][src]=1;
for(int i=0;i<2*n-1;i++){
int tmp=INF,pos;
int f;
for(int j=0;j<n;j++)
if(!used[0][j]&&dis[0][j]<tmp)
f=0,tmp=dis[0][j],pos=j;
else if(!used[1][j]&&dis[1][j]<tmp)
f=1,tmp=dis[1][j],pos=j;
if(tmp>=INF)
break;
used[f][pos]=true;
for(int j=head[pos];j+1;j=edge[j].next){
int to=edge[j].to;
if(dis[0][to]>tmp+edge[j].c)
dis[1][to]=dis[0][to],
dis[0][to]=tmp+edge[j].c,
cnt[1][to]=cnt[0][to],
cnt[0][to]=cnt[f][pos];
else if(dis[0][to]==tmp+edge[j].c)
cnt[0][to]+=cnt[f][pos];
else if(dis[1][to]>tmp+edge[j].c)
dis[1][to]=tmp+edge[j].c,
cnt[1][to]=cnt[f][pos];
else if(dis[1][to]==tmp+edge[j].c)
cnt[1][to]+=cnt[f][pos];
}
}
int ans=cnt[0][des];
if(dis[0][des]+1==dis[1][des])
ans+=cnt[1][des];
return ans;
}
void add_edge(int from,int to,int c,int index)
{
edge[index]=Node(from,to,c,head[from]);
head[from]=index;
}
int main()
{
int N;
for(scanf("%d",&N);N--;){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
int from,to,c;
for(int i=0;i<m;i++){
scanf("%d%d%d",&from,&to,&c);
add_edge(--from,--to,c,i);
}
scanf("%d%d",&src,&des);
--src,--des;
int ans=dij(src);
printf("%d\n",ans);
}
return 0;
}