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];
}