题目链接:http://poj.org/problem?id=3463
题意:给定一个图,找最短路和比最短路多1的路的条数。
思路1:将次短路也当作一种“最短”的状态,去扩展状态。这样每个点就有两种属性,次短和最短。记录次短路条数和记录最短路条数类似。
/*
我们知道Dijkstra就是不断地用已经确定最短路的节点(黑色)去松弛未确定的点(白色),
用数学归纳法很容易证明这是正确的。它的核心思想就是某个节点的最短路一定是由它前
驱节点的最短路扩展来的。那么对于次短路也可以类似的看:一个节点的次短路一定是由
它前驱节点的最短路 or 次短路扩展而来的。那么我们就可以把节点分成两层处理:一层
处理、存储最短路,另一层处理、存储次短路。这样, 用于记录状态的数组变成了二维,
放进堆中的状态也必须是”二维”的, 这里的”二维”并不是要你开个二维数组, 而是需要在
放入堆中的结构体里多加一个标记变量, 用于标识到底是最短路还是次短路, 当然, 用于
标记已经确定最短路、次短路的点的closed表同样要变成二维的。
*/
#include<cstdio>
#include<queue>
#include<iostream>
#include<vector>
#include<map>
#include<cstring>
#include<string>
#include<set>
#include<stack>
#include<algorithm>
#define cle(a) memset(a,0,sizeof(a))
#define inf(a) memset(a,0x3f,sizeof(a))
#define ll long long
#define Rep(i,a,n) for(int i=a;i<=n;i++)
using namespace std;
const int INF = ( 2e9 ) + 2;
const ll maxn = 1e3+10;
struct edge
{
int v,w,next;
}e[20*maxn];
struct node
{
int u,d,flag;
bool operator < (const node &b)const
{
return d>b.d;
}
};
int tot,head[maxn],d[maxn][2],cnt[maxn][2],vis[maxn][2];
void addedge(int u,int v,int w)
{
e[tot].v=v;
e[tot].w=w;
e[tot].next=head[u];
head[u]=tot++;
}
void dijkstra(int s,int t,int n)
{
for(int i=1;i<=n;i++)
for(int j=0;j<2;j++)
{
d[i][j]=INF;
vis[i][j]=0;
}
cnt[s][0]=cnt[s][1]=1;
d[s][0]=0;
priority_queue<node> q;
q.push(node{s,0,0});
while(!q.empty())
{
node a=q.top();q.pop();
int u=a.u;
if(vis[u][a.flag])continue;
vis[u][a.flag]=1;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].v,w=e[i].w;
if(d[v][0]>a.d+w)
{
d[v][1]=d[v][0];
cnt[v][1]=cnt[v][0];
d[v][0]=a.d+w;
cnt[v][0]=cnt[u][a.flag];
q.push(node{v,d[v][0],0});
q.push(node{v,d[v][1],1});
}
else if(d[v][0]==a.d+w)
{
cnt[v][0]+=cnt[u][a.flag];
}
else if(d[v][1]>a.d+w)
{
d[v][1]=a.d+w;
cnt[v][1]=cnt[u][a.flag];
q.push(node{v,d[v][1],1});
}
else if(d[v][1]==a.d+w)
{
cnt[v][1]+=cnt[u][a.flag];
}
}
}
if(d[t][0]+1!=d[t][1])
printf("%d\n",cnt[t][0]);
else
printf("%d\n",cnt[t][0]+cnt[t][1]);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
tot=0;
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
}
int s,t;
scanf("%d%d",&s,&t);
dijkstra(s,t,n);
}
}
思路2:从最短路上选择一个点,去“替换”最短路上的边,看能否凑成比最短路多1的路。
#include<cstdio>
#include<queue>
#include<iostream>
#include<vector>
#include<map>
#include<cstring>
#include<string>
#include<set>
#include<stack>
#include<algorithm>
#define cle(a) memset(a,0,sizeof(a))
#define inf(a) memset(a,0x3f,sizeof(a))
#define ll long long
#define Rep(i,a,n) for(int i=a;i<=n;i++)
using namespace std;
const int INF = ( 2e9 ) + 2;
const ll maxn = 1e3+10;
struct edge
{
int v,w,next;
}e[maxn*20];
struct node
{
int u,d;
bool operator < (const node &b)const
{
return d>b.d;
}
};
int head[maxn],vis[maxn],d2[maxn],d1[maxn],cnt1[maxn],cnt2[maxn],tot;
void addedge(int u,int v,int w)
{
e[tot].v=v;
e[tot].w=w;
e[tot].next=head[u];
head[u]=tot++;
e[tot].v=u;
e[tot].w=w;
e[tot].next=head[v];
head[v]=tot++;
}
void dijkstra(int s,int n,int cnt[],int d[],int flag)
{
for(int i=1;i<=n;i++)d[i]=INF;
d[s]=0;
memset(vis,0,sizeof(vis));
priority_queue<node> q;
q.push(node{s,0});
cnt[s]=1;
while(!q.empty())
{
node a=q.top();q.pop();
int u=a.u;
if(vis[u])continue;
vis[u]=1;
for(int i=head[u];i!=-1;i=e[i].next)
{
if((i&1)!=flag)continue;
int v=e[i].v,w=e[i].w;
if(vis[v])continue;
if(d[v]>d[u]+w)
{
d[v]=d[u]+w;
cnt[v]=cnt[u];
q.push(node{v,d[v]});
}
else if(d[v]==d[u]+w)
{
cnt[v]+=cnt[u];
}
}
}
}
int cul(int mindis,int n)
{
int ans=0;
for(int i=1;i<=n;i++)
{
if(d1[i]+d2[i]!=mindis)
continue;
for(int j=head[i];j!=-1;j=e[j].next)
{
if((j&1)!=0)continue;
int w=e[j].w;
int v=e[j].v;
if(d1[i]+d2[v]+w==mindis+1)
ans+=cnt1[i]*cnt2[v];
}
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
tot=0;
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
memset(d1,0,sizeof(d1));
memset(d2,0,sizeof(d2));
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
}
int s,f;
scanf("%d%d",&s,&f);
dijkstra(s,n,cnt1,d1,0);
dijkstra(f,n,cnt2,d2,1);
printf("%d\n",cul(d1[f],n)+cnt1[f]);
}
}

本文介绍了解决求最短路径及比最短路径多1的路径数量问题的两种算法思路。第一种方法通过扩展Dijkstra算法实现,将每个节点的状态分为最短路径和次短路径两种,并使用优先队列进行更新。第二种方法则通过寻找最短路径上的点,尝试替换其边来构造次短路径。
330

被折叠的 条评论
为什么被折叠?



