题目:我是超链接
题意:走出最短路的方法数,如果次短路只比最短路小1,那也是可取的。输出总的方法数
题解:
我们发现只要路径中有一条边不一样就全都不一样,那么是每条边经过不止一次的次短路?
本来考虑用A*的k短路算法,但是发现会TLE||MLE,因为发现此题的答案会超过10^8,如此之大的数量级,优先队列就把内存撑破了,而POJ2449中则有限制k<=1000,所以不会MLE。
那还是老老实实用dij吧,dij虽然也要用到优先队列,但是我们可以省略ta(比如手动小根堆什么的),注意这里我们循环了2*n-1次,为什么我们要循环2*n-1次?显然这道题中我们每一条边都需要考虑,这不是在求最短的一条,说白了是让你求出所有的可能组合,姑且就理解为其中n-1次是用来求最短路的,还有n次是次短路的
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#define INF 1e9
#define N 1005
#define M 10005
using namespace std;
int cnt[N][2],tot,nxt[M],point[N],v[M],c[M],dis[N][2],n;
bool vis[N][2];
void addline(int x,int y,int z){++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;}
void dij(int s,int t)
{
int i,j,k,fl;
memset(dis,0x7f,sizeof(dis)); memset(cnt,0,sizeof(cnt));
memset(vis,0,sizeof(vis));
dis[s][0]=0;
cnt[s][0]=1;
for (i=1;i<=2*n-1;i++)
{
int minn=0x7fffffff;k=0;
for (j=1;j<=n;j++)
if (!vis[j][0] && dis[j][0]<minn)
{
minn=dis[j][0]; k=j; fl=0;
}
else if (!vis[j][1] && dis[j][1]<minn)
{
minn=dis[j][1]; k=j; fl=1;
}
vis[k][fl]=1;
for (j=point[k];j;j=nxt[j])
{
if (dis[v[j]][0]>c[j]+minn)
{
dis[v[j]][1]=dis[v[j]][0];
dis[v[j]][0]=c[j]+minn;
cnt[v[j]][1]=cnt[v[j]][0];
cnt[v[j]][0]=cnt[k][fl];
}
else if (dis[v[j]][0]==c[j]+minn)
{
cnt[v[j]][0]+=cnt[k][fl];
}
else if (dis[v[j]][1]>c[j]+minn)
{
dis[v[j]][1]=c[j]+minn;
cnt[v[j]][1]=cnt[k][fl];
}
else if (dis[v[j]][1]==c[j]+minn)
{
cnt[v[j]][1]+=cnt[k][fl];
}
}
}
if (dis[t][0]+1==dis[t][1]) printf("%d\n",cnt[t][0]+cnt[t][1]);
else printf("%d\n",cnt[t][0]);
}
int main()
{
int T,m,i,s,t;
scanf("%d",&T);
while (T--)
{
tot=0; memset(point,0,sizeof(point));
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addline(x,y,z);
}
scanf("%d%d",&s,&t);
dij(s,t);
}
}