Description
贝茜把家搬到了一个小农场,但她常常回到FJ的农场去拜访她的朋友。贝茜很喜欢路边的风景,不想那么快地结束她的旅途,于是她每次回农场,都会选择第二短的路径,而不象我们所习惯的那样,选择最短路。 贝茜所在的乡村有R(1<=R<=100,000)条双向道路,每条路都联结了所有的N(1<=N<=5000)个农场中的某两个。贝茜居住在农场1,她的朋友们居住在农场N(即贝茜每次旅行的目的地)。 贝茜选择的第二短的路径中,可以包含任何一条在最短路中出现的道路,并且,一条路可以重复走多次。当然咯,第二短路的长度必须严格大于最短路(可能有多条)的长度,但它的长度必须不大于所有除最短路外的路径的长度。
Input
* 第1行: 两个整数,N和R,用空格隔开
* 第2..R+1行: 每行包含三个用空格隔开的整数A、B和D,表示存在一条长度为 D(1 <= D <= 5000)的路连接农场A和农场B
Output
* 第1行: 输出一个整数,即从农场1到农场N的第二短路的长度
Sample Input
4 4
1 2 100
2 4 200
2 3 250
3 4 100
Sample Output
450
输出说明:
最短路:1 -> 2 -> 4 (长度为100+200=300)
第二短路:1 -> 2 -> 3 -> 4 (长度为100+250+100=450)
HINT
Source
Gold
输入:
5 5
1 2 100
2 3 100
3 4 100
4 5 100
3 5 200
输出:
600
dijkstra:
次短路的做法和最短路径基本一致,唯一的不同点在于,在求出最短路径的情况下必须要保留下次短路径。对于Dijkstra判断中取出的每一个点,如果到它的距离大于当前该点的次短距离,则当前该点已经取到最短距离和次短距离,不进行操作,否则进行两次判断:如果小于最短边,则赋给最短边,并将最短边赋给次短边;或者如果大于最短边且小于次短边,则赋给次短边。两次完成之后均要加入队列。
//没有优先队列
#include<iostream>
#include<cstdio>
#include<cstring>
#define INF 1000000007
#define MAXN 5005
#define MAXM 222222
using namespace std;
int n,r,u,v,w,head[MAXN],cnt;
int d[MAXN][2], e,m;
bool vis[MAXN][2];
struct Edge{
int to,next,w;
}edge[MAXM*2];
void add(int fo,int to,int cost)
{
cnt++;
edge[cnt].to=to;
edge[cnt].w=cost;
edge[cnt].next=head[fo];
head[fo]=cnt;
}
int dijkstra(int s,int t)
{
int flag, u;
memset(vis, 0, sizeof(vis));
for(int i=1;i<=n;i++)
d[i][0]=d[i][1]=INF;//最短路,次短路
d[s][0]=0;
for(int i=1;i<2*n;i++)
{
int mini=INF;
for(int j=1;j<=n;j++)//dijkstra找最小的值,用最小值更新后面的
{
if(!vis[j][0] && d[j][0]<mini)
{
u=j;
flag=0;//用来记录最短路
mini=d[j][0];
}
else if(!vis[j][1] && d[j][1]<mini )
{
u=j;
flag=1;//用来记录最长路
mini=d[j][1];
}
}
if (mini == INF)
break;
vis[u][flag]=1;
for(int j=head[u];j!=-1;j=edge[j].next)
{
int v=edge[j].to;
int w=edge[j].w;//该边的权植
if(d[v][0]>mini+w)
{
d[v][1]=d[v][0];
d[v][0]=mini+w;
}
else if(d[v][1]>mini+w && d[v][0]<mini+w)
d[v][1]=mini+w;
}
}
return d[t][1];
}
int main()
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof head);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
printf("%d\n",dijkstra(1,n));
}
迷之错误…90分RE
90分RE:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define INF 0x7fffffff
#define MAXN 5555
#define MAXM 100000+10
using namespace std;
int n,m,u,v,w,head[2*MAXN],cnt=0;
int dis1[2*MAXN],dis2[2*MAXN];
struct Rec
{
int num,len;
bool operator < (const Rec &a) const
{
return len>a.len;
}
};
struct Edge{
int to,next,w;
}edge[MAXM*4];
void add(int fo,int to,int cost)
{
cnt++;
edge[cnt].to=to;
edge[cnt].w=cost;
edge[cnt].next=head[fo];
head[fo]=cnt;
}
int dijkstra(int s,int t)
{
priority_queue<Rec> que;
for(int i=2;i<=n;i++)
dis1[i]=dis2[i]=INF;//最短路,次短路
dis1[s]=0;
dis2[s]=INF;
Rec temp;
temp.len=0;
temp.num=s;
que.push(temp);
while (!que.empty())
{
Rec hd=que.top();
que.pop();
int u=hd.num; //
for(int j=head[u];j!=-1;j=edge[j].next)
{
int v=edge[j].to;//该边连接的是哪个点
int w=edge[j].w;//该边的权植
if (hd.len+w>dis2[v]) continue;//
else if(dis1[v]>hd.len+w)
{
dis2[v]=dis1[v];
dis1[v]=hd.len+w;
temp.len=dis1[v];
temp.num=v;
que.push(temp);
}
else if(dis1[v]<hd.len+w && dis2[v]>hd.len+w)//没有考虑到dis1[]==hd.len+w 的情况
{ //并不是上一个if之后 else就可以了
dis2[v]=hd.len+w;
temp.len=dis2[v];
temp.num=v;
que.push(temp);
}
// cout<<temp.num<<","<<dis1[temp.num]<<","<<dis2[temp.num]<<endl;
}
// cout<<endl;
}
return dis2[t];
}
int main()
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof head);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
printf("%d\n",dijkstra(1,n));
return 0;
}
Spfa:正着跑一边最短路,倒着跑一边最短路。那么,所有的,起点到该边一端点的距离+该边另一端点到终点的距离+该边的长度 ,取min && !=最短路。就是答案。
没有写vis[u] = 0; 这句话90分。
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define MM 100000+10
#define MN 5100
using namespace std;
int n,m,u,v,w,cnt;
int vis[MN],dis[MN][2],head[MN];
int mn =100000007;
struct Edge{
int to,next,value;
}edge[2*MM];
void add(int fn,int tn,int cost)
{
cnt++;
edge[cnt].to =tn;
edge[cnt].next=head[fn];
edge[cnt].value=cost;
head[fn]=cnt;
}
void spfa(int s,int p)
{
memset(vis,0,sizeof vis);
queue<int> que;
dis[s][p]=0;
vis[s] = 1;
que.push(s);
while(!que.empty() )
{
int u=que.front();
que.pop();
for(int j=head[u];j>0;j=edge[j].next)
{
int v=edge[j].to;
if(dis[u][p]+edge[j].value<dis[v][p] )
{
dis[v][p]= dis[u][p]+edge[j].value;
if(!vis[v])
{
vis[v]=1;
que.push(v);
}
}
}
vis[u] = 0;
}
}
int main()
{
freopen("block.in","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
memset(dis,1,sizeof dis);//因为是个二维数组,不是两个数组,不需要再次赋无穷值
spfa(1,0);
// memset(dis,1,sizeof dis);****!!!!!*********wrong不要在赋值,否则把之前求好的dis[][0]也变成无穷大了********
spfa(n,1);
for(int i=1;i<=n;i++)
{
for(int j=head[i];j;j=edge[j].next)
{
int secdis=edge[j].value+dis[i][0]+dis[edge[j].to][1];
if(secdis<mn && secdis>dis[n][0])//dis[n][0]是最短路长度
mn= secdis;
}
}
cout<<mn<<endl; //没有写这句话90分。。
}
http://www.cnblogs.com/iiyiyi/p/6078326.html最短路总结
http://www.cnblogs.com/iiyiyi/p/4706182.html#3659514例题
http://blog.youkuaiyun.com/fk_acm/article/details/51168613 其他博客,三种方法的代码