PS:可以用于剖析最短路的算法原理
计算最短路与次短路路径数,次短路长度为最短路径+1
方法记录最短路径与次短路径,并判断次短路径与最短路径之差是否唯一
方法一:反向spfa + dfs(剪枝) ===> TLE
方法二:A*搜索(第K短路) ===> MLE
方法三:spfa + 优先队列维护 + 递推 ===> AC
有向图,用 dist[][2] 分别记录最短与次短,同时更新 dp[][2]
每个点有两种状态:最短、次短(第一次被访问、第二次(多次)被访问)
节点处理:
第一次被访问:记录距离,最短状态,次数与前驱相同
第二次被访问:
比较与更新第一次的状态,记录第二种状态
多次(两次以上)被访问:
比较与更新第一次、第二次状态
状态更新,即递推过程;
思路是按照最短路距离递增序列,一层一层递推,用优先队列的用来保持递增序列;
更新第一种状态:
dp[v][0] = dp[u][0];
更新第二种状态:
dp[v][0] = dp[u][0] / dp[u][1]; [0] / [1] 与前驱状态相关:前驱是否为第一次、第二次状态
距离与当前点相等:
dp[v][0] += dp[u][0];
dp[v][1] += dp[u][0] / dp[u][1]; [0] / [1] 与前驱状态相关:前驱是否为第一次、第二次状态
好题。
计算最短路与次短路路径数,次短路长度为最短路径+1
方法记录最短路径与次短路径,并判断次短路径与最短路径之差是否唯一
方法一:反向spfa + dfs(剪枝) ===> TLE
方法二:A*搜索(第K短路) ===> MLE
方法三:spfa + 优先队列维护 + 递推 ===> AC
有向图,用 dist[][2] 分别记录最短与次短,同时更新 dp[][2]
每个点有两种状态:最短、次短(第一次被访问、第二次(多次)被访问)
节点处理:
第一次被访问:记录距离,最短状态,次数与前驱相同
第二次被访问:
比较与更新第一次的状态,记录第二种状态
多次(两次以上)被访问:
比较与更新第一次、第二次状态
状态更新,即递推过程;
思路是按照最短路距离递增序列,一层一层递推,用优先队列的用来保持递增序列;
更新第一种状态:
dp[v][0] = dp[u][0];
更新第二种状态:
dp[v][0] = dp[u][0] / dp[u][1]; [0] / [1] 与前驱状态相关:前驱是否为第一次、第二次状态
距离与当前点相等:
dp[v][0] += dp[u][0];
dp[v][1] += dp[u][0] / dp[u][1]; [0] / [1] 与前驱状态相关:前驱是否为第一次、第二次状态
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 2222;
struct Pos{
int id, dis, sta;
bool operator <( Pos e )const{
return e.dis < dis;
}
void Get( int a, int b, int c ){ id = a, dis = b, sta = c; }
};
struct Edge{
int v, w, next;
}edge[maxn*100];
int tot, head[maxn];
bool vis[maxn][2];
int n, r, dist[maxn][2], dp[maxn][2];
priority_queue<Pos>q;
int os;
void init()
{
tot = 0;
memset( head, -1, sizeof(head) );
}
inline void add_edge( int u, int v, int w )
{
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
int spfa( int src, int des )
{
while( !q.empty() )q.pop();
memset( dist, -1, sizeof(dist) );
memset( dp, 0, sizeof(dp) );
memset( vis, false, sizeof(vis) );
int i, v, len;
Pos now, next;
now.Get( src, 0, 0 );
dp[src][0] = 1; dist[src][0] = 0;
q.push( now );
while( !q.empty() )
{
now = q.top(); q.pop();
if( vis[now.id][now.sta] )continue;
vis[now.id][now.sta] = true;
for( i = head[now.id]; i != -1; i = edge[i].next )
{
v = edge[i].v;
len = now.dis + edge[i].w;
if( dist[v][0] == -1 || len < dist[v][0] )
{
if( dist[v][0] != -1 )
{
dist[v][1] = dist[v][0];
dp[v][1] = dp[v][0];
next.Get( v, dist[v][1], 1 );
q.push( next );
}
dist[v][0] = len;
dp[v][0] = dp[now.id][now.sta];
next.Get( v, len, 0 );
q.push( next );
}else if( len == dist[v][0] ){
dp[v][0] += dp[now.id][now.sta];
}else if( dist[v][1] == -1 || len < dist[v][1] ){
dist[v][1] = len;
dp[v][1] = dp[now.id][now.sta];
next.Get( v, len, 1 );
q.push( next );
}else if( len == dist[v][1] ){
dp[v][1] += dp[now.id][now.sta];
}
}
}
if( dist[des][1] - dist[des][0] == 1 )return dp[des][0] + dp[des][1];
return dp[des][0];
}
int main()
{
int cas, i, j, u, v, w;
scanf( "%d", &cas );
while( cas-- )
{
scanf( "%d%d", &n, &r );
init();
for( i = 1; i <= r; i++ )
{
scanf( "%d%d%d", &u, &v, &w );
add_edge( u, v, w );
}
int src, des;
scanf( "%d%d", &src, &des );
os = spfa( src, des );
printf( "%d\n", os );
}
return 0;
}
好题。