题意:给出n个点,m条边,求从顶点1到顶点n的次短路。
分析:首先可以知道,次短路应是在最短路的某个顶点处绕了出去,然后又回到最短路的某个顶点,而且只会绕一次(绕多次的距离肯定比绕一次的大)。再考虑次短路上的两个相邻点i和j,用d1[i]表示从源点1到i的最短距离,用d2[j]表示从j到汇点n的最短距离,那么当i和j在次短路与最短路重合的部分(即没绕出去的那部分)时,d[i]+w[i][j]+d[j]就是最短路的距离,当i或j有一个点处于绕出去的那部分时,d[i]+w[i][j]+d[j]就是次短距离。
因此,我们可以先求出所有的d1[i]和d2[j],再枚举每一条边,求出恰比最短距离大的那个d[i]+w[i][j]+d[j],也即是所求解。
代码如下:
#include <cstdio>
#include <stack>
#include <set>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <functional>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <string>
#include <map>
#include <iomanip>
#include <cmath>
#define LL long long
#define ULL unsigned long long
#define SZ(x) (int)x.size()
#define Lowbit(x) ((x) & (-x))
#define MP(a, b) make_pair(a, b)
#define MS(arr, num) memset(arr, num, sizeof(arr))
#define PB push_back
#define F first
#define S second
#define ROP freopen("input.txt", "r", stdin);
#define MID(a, b) (a + ((b - a) >> 1))
#define LC rt << 1, l, mid
#define RC rt << 1|1, mid + 1, r
#define LRT rt << 1
#define RRT rt << 1|1
#define BitCount(x) __builtin_popcount(x)
#define BitCountll(x) __builtin_popcountll(x)
#define LeftPos(x) 32 - __builtin_clz(x) - 1
#define LeftPosll(x) 64 - __builtin_clzll(x) - 1
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
using namespace std;
const double eps = 1e-8;
const int MAXN = 300 + 10;
const int MOD = 1000007;
const int N=5010;
const int M=200010;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
typedef pair<int, int> pii;
int n,m,d1[N],d2[N];
int u[M],v[M],w[M],first[N],next[M];
bool vis[N];
void build()
{
int i,j,t=m<<1;
memset(first,-1,sizeof(first));
for (i=0;i<t;i+=2){
scanf("%d%d%d",u+i,v+i,w+i);
next[i]=first[u[i]];
first[u[i]]=i;
u[i+1]=v[i]; v[i+1]=u[i]; w[i+1]=w[i];
next[i+1]=first[u[i+1]];
first[u[i+1]]=i+1;
}
}
void dij(int s,int d[])
{
int i,j;
memset(vis,false,sizeof(vis));
priority_queue<pii,vector<pii>,greater<pii> > q;
for (i=1;i<=n;d[i++]=INF);
d[s]=0;
q.push(make_pair(d[s],s));
while(!q.empty())
{
pii t=q.top(); q.pop();
int pos=t.second, val=t.first;
if (d[pos]<val) continue;
vis[pos]=true;
for (i=first[pos];i!=-1;i=next[i]) if (!vis[v[i]]) {
if (d[v[i]]>d[pos]+w[i]){
d[v[i]]=d[pos]+w[i];
q.push(make_pair(d[v[i]],v[i]));
}
}
}
}
int main()
{
int i,j;
while(~scanf("%d%d",&n,&m))
{
int a,b,c;
build();
dij(1,d1);
dij(n,d2);
int ans=INF;
for (i=1;i<=n;i++)
for (j=first[i];j!=-1;j=next[j])
{
int t=d1[u[j]]+w[j]+d2[v[j]];
if (t>d1[n] && t<ans) ans=t;
}
cout<<ans<<endl;
}
}
下面这个代码的思想是:到某个顶点v的次短路,要么是到另一个顶点u的次短路再加上u->v这条边,要么是到u的最短路再加上u->v这条边,因此所需要求的就是到所有顶点的最短路和次短路。于是在代码中不仅要记录下最短距离,还要记录下次短距离,并不断维护更新这两个距离(其实我也不太明白,照着模板敲的,程序运行时间比上一个代码要快一点~~~~~)
代码如下:
#include <cstdio>
#include <stack>
#include <set>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <functional>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <string>
#include <map>
#include <iomanip>
#include <cmath>
#define LL long long
#define ULL unsigned long long
#define SZ(x) (int)x.size()
#define Lowbit(x) ((x) & (-x))
#define MP(a, b) make_pair(a, b)
#define MS(arr, num) memset(arr, num, sizeof(arr))
#define PB push_back
#define F first
#define S second
#define ROP freopen("input.txt", "r", stdin);
#define MID(a, b) (a + ((b - a) >> 1))
#define LC rt << 1, l, mid
#define RC rt << 1|1, mid + 1, r
#define LRT rt << 1
#define RRT rt << 1|1
#define BitCount(x) __builtin_popcount(x)
#define BitCountll(x) __builtin_popcountll(x)
#define LeftPos(x) 32 - __builtin_clz(x) - 1
#define LeftPosll(x) 64 - __builtin_clzll(x) - 1
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
using namespace std;
const int N=5010;
const int M=200010;
const double eps = 1e-8;
const int MAXN = 300 + 10;
const int MOD = 1000007;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
typedef pair<int, int> pii;
int n,m,v[M],u[M],w[M],first[N],next[M];
int d1[N],d2[N];
bool vis[N];
void addedge(int a,int b,int c,int i)
{
u[i]=a; v[i]=b; w[i]=c;
next[i]=first[a];
first[a]=i;
}
void build()
{
int i,j,a,b,c,t=m<<1;
memset(first,-1,sizeof(first));
memset(vis,false,sizeof(vis));
for (i=0;i<t;i+=2){
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c,i);
addedge(b,a,c,i+1);
}
}
void dij(int s)
{
int i,j;
priority_queue<pii,vector<pii>,greater<pii> > q;
for (i=1;i<=n;d1[i]=d2[i]=INF,i++);
d1[s]=0;
q.push(make_pair(d1[s],s));
while(!q.empty())
{
pii t=q.top(); q.pop();
int val=t.first ,pos=t.second,r;
if (d2[pos]<val) continue;
//vis[pos]=true;
for (i=first[pos];i!=-1;i=next[i]) {
r=val+w[i];
if (d1[v[i]]>r){
swap(d1[v[i]],r);
q.push(make_pair(d1[v[i]],v[i]));
}
if (d2[v[i]]>r && d1[v[i]]<r){
d2[v[i]]=r;
q.push(make_pair(d2[v[i]],v[i]));
}
}
}
}
int main()
{
int i,j;
while(~scanf("%d%d",&n,&m))
{
build();
dij(1);
// for (i=1;i<=n;cout<<d1[i++]<<" "); cout<<endl;
cout<<d2[n]<<endl;
}
}