提供个样例:
输入
8 12 0 7
10 20 30 90 40 30 10 10
0 1 5
1 5 3
5 7 6
0 3 7
3 7 7
0 2 3
2 3 10
1 2 2
3 6 5
2 4 7
4 6 2
6 7 2
输出
5 120
0 3 6 7
其中5条最短路径(长14)分别为:
0 1 5 7
0 2 1 5 7
0 3 7
0 3 6 7
0 2 4 6 7
普通Dijkstra:
#include<iostream>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
const int N = 510, INF = 0x3f3f3f3f;
int g[N][N];
int num[N],w[N],count[N],dis[N],path[N];
bool book[N];
int n,m,s,d;
void Dijkstra(){
path[s] = -1;
count[s] = 1;
w[s] = num[s];
dis[s] = 0;
for(int i = 0; i < n; i++){
int minn = INF, u = -1;
for(int i = 0; i < n; i++){
if(!book[i] && minn > dis[i]){
minn = dis[i];
u = i;
}
}
book[u] = true;
for(int i = 0; i < n; i++){
if(!book[i] && g[i][u] != INF){
if(dis[i] > g[i][u] + dis[u]){
dis[i] = g[i][u] + dis[u];
count[i] = count[u];
w[i] = num[i] + w[u];
path[i] = u;
} else if(dis[i] == g[i][u] + dis[u]) {
count[i] += count[u];
if(w[i] < w[u] + num[i]){
w[i] = w[u] + num[i];
path[i] = u;
}
}
}
}
}
}
int main(){
cin>>n>>m>>s>>d;
memset(g,0x3f,sizeof(g));
memset(dis,0x3f,sizeof(dis));
for(int i = 0; i < n; i++) {
cin>>num[i];
}
for(int i = 0; i < m; i++){
int u,v,w;
cin>>u>>v>>w;
g[u][v] = g[v][u] = w;
}
Dijkstra();
cout<<count[d]<<' '<<w[d]<<endl;
int t = d;
stack<int> pathh;
while(t != -1){
pathh.push(t);
t = path[t];
}
while(pathh.size()){
int x = pathh.top(); pathh.pop();
if(x != s) cout<<' ';
cout<<x;
}
return 0;
}
堆优化Dijkstra:比普通的还慢,还出现一堆问题导致调试了一天无语死,就nm离谱
#include<iostream>
#include<queue>
#include<stack>
#include<vector>
#include<cstring>
using namespace std;
const int N = 510, INF = 0x3f3f3f3f;
struct Edge{
int v,w;
};
struct Node{
int dis;//到起点距离
int amount;//人数
int num;//当前点编号
bool friend operator <(Node a,Node b){
if(a.dis != b.dis) return a.dis > b.dis;//距离小的优先
else if(a.amount != b.amount) return a.amount < b.amount;//人数大的优先
return a.num > b.num;
}
};
priority_queue<Node> que;
vector<Edge> g[N];
int num[N],w[N],count[N],dis[N],path[N];
bool book[N];
int n,m,s,d;
void Dijkstra(){
path[s] = -1;
count[s] = 1;//默认一条最短路径
w[s] = num[s];
dis[s] = 0;
book[s] = true;
que.push({dis[s],w[s],s});
while(que.size()){
int x = que.top().num;
int len = que.top().dis;
int weight = que.top().amount;
que.pop();
//改方法会加入一些垃圾(多余的)到队列中,需要筛选
//len只会>=dis[x],大于说明之前加入队列是多余的,等于就是需要松弛的点。
//w[x] > weight,其中大于说明已经更新过(在距离相同情况下,人数多的会优先更新),之前加入队列是多余的。
if(len > dis[x] || w[x] > weight) continue;//之前由于少了w[x] > weight导致路径数count重复增加
for(auto tmp:g[x]){
int i = tmp.v;
if(dis[i] > tmp.w + dis[x]){
dis[i] = tmp.w + dis[x];
count[i] = count[x];
w[i] = w[x]+num[i];
path[i] = x;
que.push({dis[i],w[i],i});
} else if(dis[i] == tmp.w + dis[x]) {
count[i] += count[x];
if(w[i] < w[x]+num[i]){
w[i] = w[x]+num[i];
path[i] = x;
que.push({dis[i],w[i],i});
}
}
}
}
}
int main(){
cin>>n>>m>>s>>d;
fill(dis,dis+N,INF);
for(int i = 0; i < n; i++) {
cin>>num[i];
}
for(int i = 0; i < m; i++){
int u,v,w;
cin>>u>>v>>w;
//邻接表
g[u].push_back({v,w});
g[v].push_back({u,w});
}
Dijkstra();
cout<<count[d]<<' '<<w[d]<<endl;
int t = d;
stack<int> pathh;
while(t != -1){
pathh.push(t);
t = path[t];
}
while(pathh.size()){
int x = pathh.top(); pathh.pop();
if(x != s) cout<<' ';
cout<<x;
}
return 0;
}
dfs做法:剪枝后错了,输入上面样例程序会少算一条0,2,1,5,7的最短路径(因为1锁定后,2不能往1那边跑导致2到7的最短路径会少了2,1,5,7)。
dfs的代码调试一天给我心态整崩了,一直不想调试上面的样例(太多了,确实犹豫就会败北),经过使用上面的样例来艰苦的调试之后发现问题(要是早就这样调试也不用浪费这么多时间了)。
#include<iostream>
#include<cstring>
using namespace std;
const int N = 510, INF = 0x3f3f3f3f;
int num[N],path[N];
bool book[N];
int vis[N][N],a[N][N],dn[N][N];//vis i->j距离 a i->j人数 dn i->j最短路径数量
int g[N][N];//地图
int n,m,s,d,minlen = INF,sum;//sum救援队数量
bool dfs(int x,int len,int amount){//当前点,长度,救援队人数
if(x == d){
if(len < minlen || len == minlen && sum < amount){
return true;//路径有更新
}
return false;
}
if(vis[x][d] != INF) return false;//剪枝
int point = -1;//x的下一个点
int minn = INF;//x到d的最短路径
for(int i = 0; i < n; i++){
if(!book[i] && g[x][i]!=INF && minlen >= len+g[i][x]){
book[i] = true;
if(vis[i][d] != INF && len + g[x][i] + vis[i][d] < minlen) {//剪枝
dn[x][d] = dn[i][d];
minlen = len + g[x][i] + vis[i][d];
minn = g[x][i] + vis[i][d];
sum = amount + a[i][d];
a[x][d] = a[i][d] + num[x];
point = i;
} else if(vis[i][d] != INF && len + g[x][i] + vis[i][d] == minlen){//剪枝
dn[x][d] += dn[i][d];
minn = g[x][i] + vis[i][d];
if(sum < amount + a[i][d]){
sum = amount + a[i][d];
point = i;
}
} else if(vis[i][d] == INF) {
if(dfs(i,len+g[x][i],amount+num[i])) {//路径或人数有更新
point = i;
a[x][d] = a[i][d] + num[x];
}
if(minn == g[x][i] + vis[i][d]) {
dn[x][d] += dn[i][d];
} else if(minn > g[x][i] + vis[i][d]) {
minn = g[x][i] + vis[i][d];
dn[x][d] = dn[i][d];
}
}
book[i] = false;
}
}
if(point != -1) {
path[x] = point;
vis[x][d] = minn;
return true;
}
return false;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m>>s>>d;
memset(g,0x3f,sizeof(g));
memset(vis,0x3f,sizeof(vis));
for(int i = 0; i < n; i++) {
cin>>num[i];
}
for(int i = 0; i < m; i++){
int u,v,w;
cin>>u>>v>>w;
g[u][v] = g[v][u] = w;
}
book[s] = true;
path[d] = -1;
dn[d][d] = 1;//默认最短路径为一条
vis[d][d] = 0;
a[d][d] = num[d];
dfs(s,0,num[s]);
cout<<dn[s][d]<<' '<<sum<<endl;
int t = s;
while(t != -1){
if(t!=s) cout<<' ';
cout<<t;
t = path[t];
}
return 0;
}
2022.4.20标程
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#define d first
#define n second
using namespace std;
const int N = 1010;
typedef pair<int,int> PII;
struct Edge{
int to,d;
};
vector<vector<Edge>> g(N);
//cnt[i]为s到i的最短路径条数,pn[i]为s到i的最多人数
int w[N],path[N],dis[N],cnt[N],pn[N];
int n,m,s,d;
bool st[N];
void djkstra(){
memset(path,-1,sizeof path);
memset(dis,0x3f,sizeof dis);
priority_queue<PII,vector<PII>,greater<PII>> que;
que.push({0,s});
dis[s] = 0; pn[s] = w[s]; cnt[s] = 1;
while(que.size()){
auto tmp = que.top();
que.pop();
const int &u = tmp.n;
if(st[u]) continue;
st[u] = true;
for(auto edge: g[u]){
const int &v = edge.to, &dd = edge.d;
if(!st[v]){
if(dis[v] > dis[u] + dd){
dis[v] = dis[u] + dd;
path[v] = u;
cnt[v] = cnt[u];
pn[v] = w[v] + pn[u];
que.push({dis[v],v});
} else if(dis[v] == dis[u] + dd){
cnt[v] += cnt[u];
if(pn[v] < pn[u] + w[v]){
pn[v] = pn[u] + w[v];
path[v] = u;
}
}
}
}
}
cout<<cnt[d]<<' '<<pn[d]<<'\n';
stack<int> sk;
int t = d;
while(t != -1) {
sk.push(t);
t = path[t];
}
while(sk.size()) {
cout<<sk.top();
sk.pop();
if(sk.size()) cout<<' ';
}
}
int main(){
cin>>n>>m>>s>>d;
for(int i = 0; i < n; i++) cin>>w[i];
for(int i = 0; i < m; i++){
int u,v,d;
cin>>u>>v>>d;
g[u].push_back({v,d});
g[v].push_back({u,d});
}
djkstra();
return 0;
}