方法一:Dijkstra
//算法笔记 P378
//考点:Dijkstra
#include<bits/stdc++.h>
using namespace std;
const int MAXN=501;
const int INF=1000000000;
int n,m,st,ed,G[MAXN][MAXN],weight[MAXN];
int d[MAXN],w[MAXN],num[MAXN];
bool visit[MAXN]={false};
void Dijkstra(int s){
fill(d,d+MAXN,INF);
memset(w,0,sizeof(w));
memset(num,0,sizeof(num));
d[s]=0;
w[s]=weight[s];
num[s]=1;
for(int i=0;i<n;i++){
int u=-1,MIN=INF;
for(int v=0;v<n;v++){
if(visit[v]==false&&d[v]<MIN){
u=v;
MIN=d[v];
}
}
//如果未访问的点都与s不连通
if(u==-1) return ;
visit[u]=true;
for(int v=0;v<n;v++){
if(visit[v]==false&&G[u][v]!=INF){
if(d[u]+G[u][v]<d[v]){
d[v]=d[u]+G[u][v];
w[v]=w[u]+weight[v];
num[v]=num[u];
}else if(d[u]+G[u][v]==d[v]){
if(w[u]+weight[v]>w[v]){
w[v]=w[u]+weight[v];
}
num[v]+=num[u];
}
}
}
}
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d%d%d",&n,&m,&st,&ed);
fill(G[0],G[0]+MAXN*MAXN,INF);
for(int i=0;i<n;i++){
scanf("%d",&weight[i]);
}
int u,v;
for(int i=0;i<m;i++){
scanf("%d%d",&u,&v);
scanf("%d",&G[u][v]);
G[v][u]=G[u][v];
}
Dijkstra(st);
printf("%d %d",num[ed],w[ed]);
return 0;
}
方法二:Bellman-Ford
//-----方法二----------------------------------------------
Bellman-Ford方法
#include<bits/stdc++.h>
using namespace std;
const int MAXN=501;
const int INF=1000000000;
int n,m,st,ed,eight[MAXN];
int d[MAXN],w[MAXN],num[MAXN],weight[MAXN];
struct Node{
int v,dis;
Node(int _v,int _dis):v(_v),dis(_dis){
};//构造函数
};
vector<Node> Adj[MAXN];
set<int> pre[MAXN];
void Bellman(int s){
fill(d,d+MAXN,INF);
memset(w,0,sizeof(w));
memset(num,0,sizeof(num));
d[s]=0;
w[s]=weight[s];
num[s]=1;
bool flag=true;
for(int i=0;i<n-1&&flag;i++){//执行n-1次操作
flag=false;
for(int u=0;u<n;u++){//遍历所有点
for(int j=0;j<Adj[u].size();j++){//遍历每个点的所有边
int v=Adj[u][j].v;
int dis=Adj[u][j].dis;
if(d[u]+dis<d[v]){
d[v]=d[u]+dis;
//有边可以被松弛了 ,说明数组d中有值没有达到最优
flag==true继续优化
flag=true;
w[v]=w[u]+weight[v];
num[v]=num[u];
pre[v].clear();
pre[v].insert(u);
}else if(d[u]+dis==d[v]){
if(w[u]+weight[v]>w[v]){
w[v]=w[u]+weight[v];
//说明数组w中有值没有达到最优
}
pre[v].insert(u);
//重新统计num[v]
num[v]=0;
set<int>::iterator it;
for(it=pre[v].begin();it!=pre[v].end();it++){
num[v]+=num[*it];
}
//表示最短路径条数的num数组的num[v]可能发生改变
//flag==true继续优化
flag=true;
}
}
}
}
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d%d%d",&n,&m,&st,&ed);
for(int i=0;i<n;i++){
scanf("%d",&weight[i]);
}
int u,v,wt;
for(int i=0;i<m;i++){
scanf("%d%d%d",&u,&v,&wt);
Adj[u].push_back(Node(v,wt)) ;
Adj[v].push_back(Node(u,wt));
}
Bellman(st);
printf("%d %d",num[ed],w[ed]);
return 0;
}
方法三:SPFA
//--------SPFA方法-------- ----------------
#include<bits/stdc++.h>
using namespace std;
const int MAXN=501;
const int INF=1000000000;
int n,m,st,ed,weight[MAXN];
int d[MAXN],w[MAXN],num[MAXN],cnt[MAXN];
bool inq[MAXN]={false};
set<int> pre[MAXN];
struct Node{
int v,dis;
Node(int _v,int _dis):v(_v),dis(_dis){
};//构造函数
};
vector<Node> Adj[MAXN];
bool SPFA(int s){
fill(d,d+MAXN,INF);
memset(w,0,sizeof(w));
memset(num,0,sizeof(num));
queue<int> Q;
Q.push(s);
//s在队列里
inq[s]=true;
d[s]=0;
w[s]=weight[s];
num[s]=1;
cnt[s]=1;//源点入队次数+1
while(!Q.empty()){
int u=Q.front();
Q.pop();
inq[u]=false;
for(int j=0;j<Adj[u].size();j++){
int v=Adj[u][j].v;
int dis=Adj[u][j].dis;
if(d[u]+dis<d[v]){
d[v]=d[u]+dis;
w[v]=w[u]+weight[v];
pre[v].clear();
pre[v].insert(u);
num[v]=num[u];
if(!inq[v]){
Q.push(v);
//v的入队次数+1
cnt[v]++;
inq[v]=true;
}
}else if(d[u]+dis==d[v]){
if(w[u]+weight[v]>w[v]){
w[v]=w[u]+weight[v];
}
pre[v].insert(u);
num[v]=0;
set<int>::iterator it;
for(it=pre[v].begin();it!=pre[v].end();it++){
num[v]+=num[*it];
}
//无论w[v]是否改变,num[v]都有可能改变,所以入队
if(!inq[v]){
Q.push(v);
cnt[v]++;
inq[v]=true;
}
}
//只要某一点入队次数>=n
//则原图中有负环,则不可得到结果
if(cnt[v]>=n) return false;
}
}
return true;
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d%d%d",&n,&m,&st,&ed);
for(int i=0;i<n;i++){
scanf("%d",&weight[i]);
}
int u,v,wt;
for(int i=0;i<m;i++){
scanf("%d%d%d",&u,&v,&wt);
Adj[u].push_back(Node(v,wt));
Adj[v].push_back(Node(u,wt));
}
bool ok=SPFA(st);
if(ok) printf("%d %d",num[ed],w[ed]);
else printf("有负环!");
return 0;
}