HDU3191 次短路条数

/*
    求s到t的最短路与次短路(这里要求只比最短路多1)的条数之和

    联想到最小,次小的一种更新关系:
    if(x<最小)更新最小,次小
    else if(==最小)更新方法数
    else if(x<次小)更新次小
    else if(x==次小)更新方法数

    同时记录s到u最短,次短路及方法数
    用一个堆每次取最小的,更新完后再入堆
    还是那个原理,第一次遇到的就是最优的,然后vi标记为真
    方法数注意是加法原理,不是乘法
    \
    -- u -- v  所以是加法原理
    /
*/
//单开一个数组来记录数目
//理解了一下。。。还要回去debug..
//http://blog.csdn.net/u013368721/article/details/36682223

#include<iostream>
#include<cstring>
#include<string.h>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#define maxm 200
#define maxn 200
#define MAXN 200
#define inf 0x3f3f3f
using namespace std;
int em;
int head[maxn];
bool vis[2][maxn];
int d[maxn];
int d2[maxn];
int cnt[2][maxn];

struct Edge
{
    int u,len,next;
}edge[2*MAXN];

void addEdge(int v,int w,int c)
{
    edge[em].u=w;
    edge[em].len=c;
    edge[em].next=head[v];
    head[v]=em;
    em++;
}


struct Node
{
    int a;
    int kind;
    int len;
    friend bool operator <(Node a,Node b)
    {
        if(a.len!=b.len)
        return a.len>b.len;
        return a.a>b.a;//过了,但是这里为什么要按字典序排序
    }
}start,v,tem;


priority_queue <Node>q;//0为最短路,1为次短路。。kind为加入的边的种类??开数组保存
void dij(int s,int t)
{
    while(!q.empty()) q.pop();
    for(int i=0;i<=t;i++)
        d[i]=inf,d2[i]=inf,cnt[0][i]=0,cnt[1][i]=0;
    memset(vis,false,sizeof(vis));
    start.a=s;
    start.kind=0;
    start.len=0;
    cnt[0][s]=1;d[s]=0;
    q.push(start);
    while(!q.empty())
    {
        v=q.top();
        int u=v.a;
        int dis=v.len;
        int kind=v.kind;
        q.pop();
        if(vis[kind][u]) continue;
        vis[kind][u]=1;
        for(int i=head[u];~i;i=edge[i].next)
        {
            int vi=edge[i].u;
            int tmp=dis+edge[i].len;
        if(tmp<d[vi])
        {
            if(d[vi]<d2[vi])
                {
                    d2[vi]=d[vi];
                    cnt[1][vi]=cnt[0][vi];
                    tem.a=vi;
                    tem.len=d2[vi];
                    tem.kind=1;
                    q.push(tem);
                }
                d[vi]=tmp;
                cnt[0][vi]=cnt[0][u];
                tem.a=vi;
                tem.len=tmp;
                tem.kind=0;
                q.push(tem);
        }
        else if(tmp==d[vi])
        {
            cnt[0][vi]+=cnt[0][u];
        }
        else if(tmp<d2[vi])
        {
            d2[vi]=tmp;
            cnt[1][vi]=cnt[kind][u];
            tem.a=vi;
            tem.len=d2[vi];
            tem.kind=1;
            q.push(tem);
        }
        else if(tmp==d2[vi])
        {
            cnt[1][vi]+=cnt[kind][u];
        }
        }
    }
    cout<<d2[t]<<" "<<cnt[1][t]<<endl;
}


int main()
{
//    freopen("input.txt","r",stdin);
    int n,m,s,a,b,e,w;
    while(scanf("%d%d%d%d",&n,&m,&s,&e)!=EOF)
    {
        memset(head,-1,sizeof(head));
        em=0;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&a,&b,&w);
            addEdge(a,b,w);
        }
        dij(s,e);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值