次短路

1.poj Sightseeing

http://poj.org/problem?id=3463

2.HDU How Many Paths Are There

http://acm.hdu.edu.cn/showproblem.php?pid=3191

dis[x][2]:dis[x][0]表示起点到x的最短路、dis[x][1]表示起点到x的次短路;

num[x][2]:num[x][0]表示起点到x的最短路条数、num[x][1]表示起点到x的次短路的条数;

vis[x][2]对应于x和0、1功能为记录该点是否被访问!

     每次更新有四种情况:

      1.if(x<最小)把最小值赋给次小值,更新最小值;
      2.else if(x==最小)更新方法数;
      3.else if(x<次小)更新次小;
      4.else if(x==次小)更新方法数;

问题:

1.更新次数,为2*n-1,因为每次更新找到一个最小值或者次小值,最小+次小共2*n个,其中源点已经被赋值

2.找到当前的最小路径点,然后更新其他值

3.更新的4种情况的具体实现,详见代码

4.板子有潜在的危险

板子:可轻易变换成优先队列优化形式,

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int INF=0x3f3f3f3f;
const int VM=55;
const int EM=10010;

struct Edge{
    int to,nxt;
    int cap;
}edge[EM<<1];

int vis[VM][2],dis[VM][2];  // dis[i][0]:到点i的最短路   dis[i][1]:到点j的次短路
int head[VM],num[VM][2];  // count[i][0]:到点i的最短路的路数   len[i][1]:到点j的次短路的路数
int n,m,cnt;

void addedge(int cu,int cv,int cw){
    edge[cnt].to=cv;
    edge[cnt].cap=cw;
    edge[cnt].nxt=head[cu];
    head[cu]=cnt++;
}

void Dijkstra(int src,int des){
    memset(vis,0,sizeof(vis));
    memset(num,0,sizeof(num));
    int i=0;
    for(i=1;i<=n;i++){
        dis[i][0]=INF;
        dis[i][1]=INF;
    }
    dis[src][0]=0;
    num[src][0]=1;
    int j,k,tmp,flag;
    for(i=1;i<=2*n-1;i++){
        tmp=INF;    // 找新的最短路和次短路
        for(j=1;j<=n;j++)
            if(!vis[j][0] && tmp>dis[j][0]){
                k=j;
                flag=0;
                tmp=dis[j][0];
            }else if(!vis[j][1] && tmp>dis[j][1]){
                k=j;
                flag=1;
                tmp=dis[j][1];
            }
        if(tmp==INF)    // 如果最短路和次短路都不存在,则退出for循环
            break;
        vis[k][flag]=1;
        for(j=head[k];j!=-1;j=edge[j].nxt){ // 更新和点k相连的边
            int v=edge[j].to;
            if(dis[v][0]>tmp+edge[j].cap){  // 比最短路短
                dis[v][1]=dis[v][0];
                num[v][1]=num[v][0];
                dis[v][0]=tmp+edge[j].cap;
                num[v][0]=num[k][flag];
            }else if(dis[v][0]==tmp+edge[j].cap){   // 等于最短路
                num[v][0]+=num[k][flag];
            }else if(dis[v][1]>tmp+edge[j].cap){    // 比次短路短
                dis[v][1]=tmp+edge[j].cap;
                num[v][1]=num[k][flag];
            }else if(dis[v][1]==tmp+edge[j].cap){   // 等于次短路
                num[v][1]+=num[k][flag];
            }
        }
    }
    printf("%d %d\n",dis[des][1],num[des][1]);
}

板子的潜在危险:

Dijkstra成立的条件是,当前选出的可操作节点,并不会被后面的节点,更新,所以

首先问题在,第2步,这里潜在对节点定好了优先级,就如果节点2,节点3都是当前最短路径点,我就拿出节点2来操作,没有考虑,节点3会不会对节点2造成影响,

1.如果边权>=1,板子没有问题,

2.如果边权<0,Dijkstra,本身不成立,

3.如果边权=0,这样就要对,所有的节点进行拓扑排序,然后节点优先级,以拓扑排序先后为准,选取路径最小值,拓扑序靠前的,保证当前节点的正确性,

       for(j=1;j<=n;j++)
            if(!vis[j][0] && (tmp>dis[j][0]||tmp==dis[j][0]&&top[j]<top[k])){
                k=j;
                flag=0;
                tmp=dis[j][0];
            }else if(!vis[j][1] && <span style="font-family: arial;">(tmp>dis[j][0]||(tmp==dis[j][0]&&top[j]<top[k])</span><span style="font-family: arial;">){</span>
                k=j;
                flag=1;
                tmp=dis[j][1];
            }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值