这是一道单源最短路。
任务一:在跑最短路算法时不经过故障边即可。
任务二:S1直接跑最短路。
S2用到一个关于最短路的性质。当题目需要输出最短路,我们就要在跑最短路时记录更新每个节点的前驱节点,表示走了这条边,那么只要这些边不被破坏,两点间的最短路就不会变。当要求我们求次短路时,可以枚举起点到终点的最短路的每条边,之后在不经过这条边的情况下跑最短路算法,就可以得到次短路,要注意题目是否要求求严格次短路。时间复杂度在原有最短路算法的基础上再乘一个n。事实上当我们把起点到每一个点的最短路用记录前驱的方式表达出来后,将得到一颗树,这棵树也叫作最短路树,是非常有用的一种树。
只有三组数据,虽说1A,但心里是很慌的......
// q.c
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
const int M=50,INF=(int)1e9;
int n,s,t,p,b[7],fa[M+3],f[M+3][M+3][2],g[M+3][M+3],dis[M];
bool done[M+3];
struct Node {
int id,w;
bool operator < (const Node &A) const {
return w>A.w;
}
};
void reset(int x) {
for(int k=1;k<=p;k++) {
int i=b[k];
for(int j=1;j<=n;j++)
f[i][j][1]=f[j][i][1]=x;
}
}
int dijstra(int x) {
memset(dis,0x7f,sizeof(dis));
memset(done,0,sizeof(done));
priority_queue<Node> q;
dis[s]=0;
q.push((Node){s,dis[s]});
int u,v,w;
while(!q.empty()) {
Node nd=q.top(); q.pop();
u=nd.id,w=nd.w;
if(done[u]) continue;
done[u]=true;
for(int i=1;i<=g[u][0];i++) {
v=g[u][i];
if(!done[v]&&f[u][v][0]&&!f[u][v][1]&&w+f[u][v][0]<dis[v]) {
dis[v]=w+f[u][v][0];
if(x) fa[v]=u;
q.push((Node){v,dis[v]});
}
}
}
return dis[t];
}
int solve() {
int x=t,w=INF;
while(fa[x]) {
f[x][fa[x]][1]=f[fa[x]][x][1]=1;
w=min(w,dijstra(0));
f[x][fa[x]][1]=f[fa[x]][x][1]=0;
x=fa[x];
}
return w;
}
int main() {
freopen("route.in","r",stdin);
freopen("route.out","w",stdout);
scanf("%d%d%d",&n,&s,&t);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) {
scanf("%d",&f[i][j][0]);
g[i][++g[i][0]]=j;
}
scanf("%d",&p);
for(int i=1;i<=p;i++) scanf("%d",&b[i]);
reset(1);
int ans0=dijstra(0);
reset(0);
int ans1=dijstra(1);
int ans2=solve();
printf("%d %d %d\n",ans0,ans1,ans2);
return 0;
}