次短路
定义:找出第二短的路径长,次于最短路。
思路:求两次最短路,一个是到起点的最短路,一个是到终点的最短路。然后遍历每一条边,每一条边的两个点分别到终点和起点的最短路的和+边的长度,如果这个和大于最短路,就让ans取这些路中的最小值就好了。
LightOJ - 1099
题意:给你n个点,m条边,让你求出次短路(次短路的长度要小于最短路,相同的不算)
思路:次短路的思路。
代码:
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <cstdlib>
#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
const int maxn=5000;
const int maxm=1e5;
const int inf=1e8*5+5;
int dis[maxn+5];
int dis1[maxn+5];
bool vis[maxn+5];
int head[maxm+5];
int cnt[maxn+5];
int n,m;
int t;
struct node
{
int v,w;
int nxt;
}mp[maxm*2];
struct nod
{
int u,v;
int w;
}q[maxm+10];
int count1;
void add(int u,int v,int w)
{
mp[count1].nxt=head[u];
mp[count1].v=v;
mp[count1].w=w;
head[u]=count1++;
}
void spfa(int u)
{
queue<int>que;
for(int i=1;i<=n;i++)
{
dis[i]=inf;
vis[i]=0;
cnt[i]=0;
}
que.push(u);
vis[u]=1;
cnt[u]++;
dis[u]=0;
while(que.size())
{
int u=que.front();
que.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=mp[i].nxt)
{
int v=mp[i].v;
if(dis[v]>dis[u]+mp[i].w)
{
dis[v]=dis[u]+mp[i].w;
if(!vis[v])
{
cnt[v]++;
if(cnt[v]>=n)
{
return ;
}
vis[v]=1;
que.push(v);
}
}
}
}
return ;
}
int main()
{
int t;
int count2=0;
scanf("%d",&t);
while(t--)
{
count1=0;
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&q[i].u,&q[i].v,&q[i].w);
add(q[i].u,q[i].v,q[i].w);
add(q[i].v,q[i].u,q[i].w);
}
spfa(1);
for(int i=1;i<=n;i++)
{
dis1[i]=dis[i];
}
spfa(n);
int ans=inf;
//核心
for(int i=1;i<=m;i++)
{
//每一条边的两个点分别到终点和起点的最短路的和+边的长度
if(dis1[q[i].u]+dis[q[i].v]+q[i].w>dis1[n])
{
ans=min(ans,dis1[q[i].u]+dis[q[i].v]+q[i].w);
}
if(dis1[q[i].v]+dis[q[i].u]+q[i].w>dis1[n])
{
ans=min(ans,dis1[q[i].v]+dis[q[i].u]+q[i].w);
}
}
printf("Case %d: %d\n",++count2,ans);
}
return 0;
}
总结:突然有点区分不开最小生成树和最短路了,最小生成树要通过所有的点,最短路不一定。