次短路计数

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速度还是差了挺多的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值