前言:关于找到最短路径上经过的边有两种方法
一种是从起点出发找一次最短路径,再从终点出发找一次最短路径
另一种是在找最短路径时标记下一个点
例题1:可怜的草坪
题目描述
小C的大学很大,从寝室到食堂要走很长一段路,很多的草坪位于这些路上。大家从寝室出发时,都喜欢从走最少的路达到食堂,哪些位于最短路上的草坪都要被踩踏,小C希望你帮他算算,有多少段草坪会经常被踩踏?
输入 输入第一行,两个整数n,m。其中1为寝室,n为食堂。 接下来m行,每行三个整数a,b,c,表示有段草坪从a到b,长度为c。 输出 输出最短的距离是多少和m段草坪中有多少段经常被踩踏。
#include
using namespace std;
const int INF=10005;
const int MAX_V=20005;
const int MAX_N=200005;
struct edge{int to,cost;};
typedef pair<int,int>P;
vector G[MAX_N];
vector H[MAX_N];
int d[MAX_V],f[MAX_V];
int v;
void dijikstra(int s){
priority_queuevector
,greater
>que;
fill(d,d+v,INF);
d[s]=0;
que.push(P(0,s));
while(!que.empty()){
P p=que.top();que.pop();
int v1=p.second;
if(d[v1]
continue;
for(int i=0;iif(d[e.to]>d[v1]+e.cost){
d[e.to]=d[v1]+e.cost;
que.push(P(d[e.to],e.to));
}
}
}
}
void dijikstra1(int s){
priority_queuevector
,greater
>que;
fill(f,f+v,INF);
f[s]=0;
que.push(P(0,s));
while(!que.empty()){
P p=que.top();que.pop();
int v1=p.second;
if(f[v1]
continue;
for(int i=0;iif(f[e.to]>f[v1]+e.cost){
f[e.to]=f[v1]+e.cost;
que.push(P(f[e.to],e.to));
}
}
}
}
int main(){
int n;
cin>>v>>n;
for(int i=0;iint a,b,c;
scanf("%d%d%d",&a,&b,&c);
a=a-1;b=b-1;
edge e,e2;
e.to=b;e.cost=c;
e2.to=a;e2.cost=c;
G[a].push_back(e);
H[b].push_back(e2);
}
dijikstra(0);
dijikstra1(v-1);
int ans=d[v-1];
printf("%d ",ans);
int cnt=0;
for(int i=0;ifor(int j=0;jif(e.cost+d[i]+f[e.to]==ans)cnt++;
}
}
printf("%d",cnt);
return 0;
}
例题2:奶牛的延时计划
题目描述:
Lay博士每天早上都要从家到谷仓.他的农场里有N块土地,编号1~N,Lay博士的家在1号,谷仓在N号.有M条双向路径连接它们,且没有重边,经过每条路都要一定时间.Lay博士智商非常高,所以他每次都会走最短的路线,使到达谷仓时间最短.
Lay博士的奶牛都很调皮,想使Lay博士到达谷仓尽可能晚.它们计划在M条路上的某一条路上铺设草堆,使通过这条边的时间加倍.奶牛们想选择一条边,使Lay博士延迟到达谷仓的时间尽可能大.输入: 两个整数,N(1<=N<=100),M(1<=M<=10000).
接下来M行,每行三个整数a,b,c表示a到b之间的路径,通过的时间为c(1<=c<=106).
输出:输出一个整数,表示奶牛们最多能使Lay博士延迟的时间.
贴上hqz大犇的代码(解法二)
#include
#include
#include
#define M 105
#define INF 0x3f3f3f3f
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;int n,m,first=1,ans;int pre[M],dis[M],cost[M][M];bool mark[M];queue<int>Q;vector<int>edge[M];int SPFA() {while(!Q.empty())Q.pop();
memset(dis,63,sizeof(dis));
memset(mark,0,sizeof(mark));
Q.push(1);mark[1]=1;dis[1]=0;pre[1]=0;
while(!Q.empty()) {
int now=Q.front();
Q.pop();
mark[now]=0;
FOR(i,0,edge[now].size()-1){
int to=edge[now][i];
if(dis[to]>dis[now]+cost[to][now]) {
if(first) pre[to]=now;
dis[to]=dis[now]+cost[now][to];
if(!mark[to]) {
mark[to]=1;
Q.push(to);
}
}
}
}
return dis[n];
}
int main(){
scanf("%d%d",&n,&m);
FOR(i,1,m){
int s,t,v;
scanf("%d%d%d",&s,&t,&v);
edge[s].push_back(t);
edge[t].push_back(s);
cost[s][t]=v,cost[t][s]=v;
}
int primor_way=SPFA();
first=0;
for(int x=n;;x=pre[x]){
if(pre[x]==0) break;
cost[pre[x]][x]=cost[x][pre[x]]=2*cost[x][pre[x]];
int res=SPFA();
cost[pre[x]][x]=cost[x][pre[x]]=cost[x][pre[x]]/2;
ans=max(ans,res-primor_way);
}
printf("%d\n",ans);
}