1716:次短路计数
时间限制: 2000 ms 内存限制: 65536 KB
提交数: 86 通过数: 16
【题目描述】
给定一张包含nn个点、mm条边的有向图,并且给定起始点ss和终点tt,求从ss到tt的最短路线和比最短路线多一个单位距离的路线的总方案数。(两条路线A、BA、B不同当且仅当存在一条边 ∈A∈A且∉B∉B)。
【输入】
输入包含多组数据。
第一行包含一个整数TT表示测试数据的个数。对于每组测试数据:
第一行包含两个整数n,mn,m,分别表示图中点的数量和边的数量。
接下来mm行,每行包含33个整数x,y,wx,y,w,表示有一条从xx连向yy的(x≠yx≠y)权值为ww的单向边。
最后一行包含两个整数s,ts,t,数据保证s≠ts≠t且至少有一条从ss到tt的路线。
【输出】
对于每组数据,输出一个整数表示总方案数,保证所有数据都在109109的范围内。
【输入样例】
2 5 8 1 2 3 1 3 2 1 4 5 2 3 1 2 5 3 3 4 2 3 5 4 4 5 3 1 5 5 6 2 3 1 3 2 1 3 1 10 4 5 2 5 2 7 5 2 7 4 1
【输出样例】
3 2
【提示】
【数据规模及约定】
对于100%的数据,满足2≤n≤1000,1≤m≤10000,1≤x,y,s,t≤n,1≤c≤10002≤n≤1000,1≤m≤10000,1≤x,y,s,t≤n,1≤c≤1000。
这道题目就是类似dp,利用dijkistra求出最短路和次短路,然后利用加法原理统计方案,然后看代码,逻辑还是比较清晰的
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int head[2005],nxt[20005],to[20005],wei[20005],dis[2005][2],ans[2005][2],vis[2005][2],cnt=1,n,m,s,t;
int read(){
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
int res=0;
while(ch>='0'&&ch<='9'){
res=res*10+ch-'0';
ch=getchar();
}
return res;
}
void add(int u,int v,int w){
nxt[++cnt]=head[u];
to[cnt]=v;
head[u]=cnt;
wei[cnt]=w;
}
void init(){
memset(head,0,sizeof head);
memset(nxt,0,sizeof nxt);
memset(to,0,sizeof to);
memset(wei,0,sizeof wei);
memset(dis,0x3f,sizeof dis);
memset(ans,0,sizeof ans);
memset(vis,0,sizeof vis);
cnt=1;
}
struct node{
int p,d,c;
bool operator < (const node& other)const{
return d>other.d;
}
bool operator > (const node& other)const{
return d<other.d;
}
};
priority_queue<node> q;
void solve(){
while(!q.empty())q.pop();
dis[s][0]=0;
ans[s][0]=1;
q.push((node){s,0,0});
while(!q.empty()){
node top=q.top();
q.pop();
int u=top.p,c=top.c,d=top.d;
if(vis[u][c])continue;
vis[u][c]=true;
for(int i=head[u];i;i=nxt[i]){
int v=to[i],w=wei[i];
if(dis[v][0]>d+w){
if(dis[v][0]!=0x3f3f3f3f){
dis[v][1]=dis[v][0];
ans[v][1]=ans[v][0];
q.push((node){v,dis[v][1],1});
}
dis[v][0]=d+w;
ans[v][0]=ans[u][c];
q.push((node){v,dis[v][0],0});
}else if(dis[v][0]==d+w){
ans[v][0]+=ans[u][c];
}else if(dis[v][1]>d+w){
dis[v][1]=d+w;
ans[v][1]=ans[u][c];
q.push((node){v,dis[v][1],1});
}else if(dis[v][1]==d+w){
ans[v][1]+=ans[u][c];
}
}
}
}
int main(){
int T=read();
while(T--){
init();
n=read(),m=read();
for(int i=1;i<=m;i++){
int u=read(),v=read(),w=read();
add(u,v,w);
}
s=read(),t=read();
solve();
if(dis[t][1]==dis[t][0]+1){
printf("%d\n",ans[t][0]+ans[t][1]);
}else{
printf("%d\n",ans[t][0]);
}
}
return 0;
}
有一个坑点是,dijkistra的判重部分必须要用标记数组,不能用dis[u][1]<d的形式,否则可能会重复累加答案,还有就是,这题最好用下快读,快读跟scanf速度还是差了挺多的