之前很认真地看了用优先队列来实现Dijkstra这块,借鉴了小白书上的代码模板后,便拿这道题来试试水了。这道题的大意就是问你从地点1到地点2有多少条满足条件的路径(假设该路径经过 1->...-> a -> b ->...-> 2,那么d[b]必须小于d[a],其中d[b],d[a]分别是指 b,a 到地点2的最短距离),所以大体做法就是先求出以2为起点的单源最短路径,然后利用深搜dfs(v)表示 v顶点到2的满足以上条件的路径数,最后答案便是dfs(1),当然要加个记忆化。

  因为我主要是拿来练习Dijkstra,所以深搜这部分可以不用变,先附上用邻接矩阵来实现的最原始的Dijkstra:

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int INF= 0x3fffffff;
const int maxN= ; int n, w[maxN+][maxN+]; bool vis[maxN+];
int d[maxN+];
void Dijkstra(int u){
memset(vis,,sizeof(vis));
for(int i=; i<=n; ++i)
d[i]= INF;
d[u]= ;
while(){
int x, m =INF;
for(int y=; y<=n; ++y)
if(!vis[y] && m>d[y]) m= d[x=y];
if(m==INF) break;
vis[x]= ;
for(int y=; y<=n; ++y)
if(w[x][y]!=INF) d[y]= min(d[y],d[x]+w[x][y]);
}
} int dp[maxN+];
int dfs(int v){
if(dp[v]!=-) return dp[v];
if(v==) return ;
dp[v]= ;
for(int i=; i<=n; ++i)
if(w[v][i]!=INF && d[i]<d[v]) dp[v]+= dfs(i);
return dp[v];
} int main(){
int m,i,j,x,y,z;
while(scanf("%d",&n),n){
scanf("%d",&m);
for(i=; i<=maxN; ++i)
for(j=i; j<=maxN; ++j)
w[i][j]= w[j][i]= INF;
while(m--){
scanf("%d%d%d",&x,&y,&z);
w[x][y]= w[y][x]= z;
}
Dijkstra();
memset(dp,-,sizeof(dp));
printf("%d\n",dfs());
}
return ;
}

  然后dfs部分保持不变,Dijkstra改用邻接表+优先队列来实现,小白书上也有比较详细的代码了,可是这道题是无向图,而小白书上的代码仅仅适用于有向图,需要作少许的更改(这一点点更改已经让我痛苦了好久T.T ,我不想再回忆了T.T)。

  在邻接表的读入这部分调试了好久,因为对于题目中的每条边都需要手动把它拆成两条边再存进结点数组和边数组中,刘汝佳的书中读入和邻接表的预处理是合在一起的(后来才发现这对我调试带来了大大的不便),所以在最终的代码里我把它们分开来了,感觉代码清爽多了。

  (因为dfs中需要访问两结点间是否存在边,如果单纯去遍历邻接表的话恐怕会超时,所以终究要用到一个邻接矩阵edge[][],只不过该矩阵用bool 来定义即可,因为只需记录两结点间是否有边(1/0),边权值已存放在了w[]数组中):

 #include<cstdio>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int INF= 0x3fffffff;
const int maxN= ;
const int maxM= ; int n,m;
bool edge[maxN+][maxN+];
int first[maxN+];
int u[maxM+], v[maxM+], w[maxM+], Next[maxM+]; //边读入邻接表中:
void read_graph()
{
memset(first,-,sizeof(first)); //一开始我是这个读法,把所有的边整体复制到原始边的最后面,思路是没有错,
//但就是因为少了 v[e+m]= u[e]的复制足够让我几乎想破了脑袋也想不出来,
//因为当时是凌晨2点多做的,头脑不清醒以为边的终点 v[e]用不上所以不用复制,
//但Dijkstra中是所有的信息都要用到的,包括 起点,终点,边权值,三者缺一不可!
/* for(int e=0; e<m; ++e)
{
scanf("%d%d%d",u+e,v+e,w+e);
u[e+m]= v[e];
v[e+m]= u[e]; //就是少了这个,结果错成狗!
w[e+m]= w[e];
edge[u[e]][v[e]]= edge[v[e]][u[e]]= true;
}*/ //然后这种读法是每读入一条边,就把它紧凑地复制到下一个位置,注意 e每次循环是加 2的
for(int e=; e<*m; e+=)
{
scanf("%d%d%d",u+e,v+e,w+e);
u[e+]= v[e];
v[e+]= u[e]; //记得也要有这个,不然同样错成狗!
w[e+]= w[e];
edge[u[e]][v[e]]= edge[v[e]][u[e]]= true; /* Next[e]= first[u[e]]; //一边读入一边处理也可以,
first[u[e]]= e; Next[e+1]= first[u[e+1]];
first[u[e+1]]= e+1;*/
} //把邻接表的处理放在后面就更清晰,代码更清爽。
for(int e=; e<*m; ++e)
{
Next[e]= first[u[e]];
first[u[e]]= e;
}
} //优先队列所需的一切数据结构
typedef pair<int,int> pii;
priority_queue<pii, vector<pii>, greater<pii> > q;
bool done[maxN+];
int d[maxN+]; void Dijkstra(int u){
memset(done,,sizeof(done));
for(int i=; i<=n; ++i)
d[i]= INF;
d[u]= ;
q.push(pii(d[u],u));
while(!q.empty()){
int x= q.top().second; q.pop();
if(done[x]) continue;
done[x]= ;
for(int e= first[x]; e!= -; e= Next[e])
if(d[x]!=INF && d[v[e]] > d[x]+w[e]){
d[v[e]]= d[x]+w[e];
q.push(pii(d[v[e]],v[e]));
}
}
} int dp[maxN+];
int dfs(int v){
if(dp[v]!=-) return dp[v];
if(v==) return ;
dp[v]= ;
for(int i=; i<=n; ++i)
if(edge[v][i] && d[i]<d[v]) dp[v]+= dfs(i);
return dp[v];
} int main(){
while(scanf("%d",&n),n){
scanf("%d",&m);
memset(edge,,sizeof(edge));
read_graph();
Dijkstra();
memset(dp,-,sizeof(dp));
printf("%d\n",dfs());
}
return ;
}

hdu 1142 用优先队列实现Dijkstra的更多相关文章

  1. hdu 1142 最短路+记忆化

    最短路+记忆化搜索HDU 1142 A Walk Through the Forest链接:http://acm.hdu.edu.cn/showproblem.php?pid=1142 > 题意 ...

  2. poj 1511 优先队列优化dijkstra *

    题意:两遍最短路 链接:点我 注意结果用long long #include<cstdio> #include<iostream> #include<algorithm& ...

  3. POJ 1511 Invitation Cards (ZOJ 2008) 使用优先队列的dijkstra

    传送门: http://poj.org/problem?id=1511 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1008 ...

  4. HDU 1535 Invitation Cards(逆向思维+邻接表+优先队列的Dijkstra算法)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1535 Problem Description In the age of television, n ...

  5. HDU 2544最短路 【dijkstra 链式前向星+优先队列优化】

    最开始学最短路的时候只会用map二维数组存图,那个时候还不知道这就是矩阵存图,也不懂得效率怎么样 经过几个月的历练再回头看最短路的题, 发现图可以用链式前向星来存, 链式前向星的效率是比较高的.对于查 ...

  6. hdu 1142(DFS+dijkstra)

    #include<iostream> #include<cstdio> #include<cmath> #include<map> #include&l ...

  7. HDU 1142 A Walk Through the Forest(dijkstra+记忆化DFS)

    题意: 给你一个图,找最短路.但是有个非一般的的条件:如果a,b之间有路,且你选择要走这条路,那么必须保证a到终点的所有路都小于b到终点的一条路.问满足这样的路径条数 有多少,噶呜~~题意是搜了解题报 ...

  8. HDU 1142 A Walk Through the Forest(Dijkstra+记忆化搜索)

    题意:看样子很多人都把这题目看错了,以为是求最短路的条数.真正的意思是:假设 A和B 是相连的,当前在 A 处, 如果 A 到终点的最短距离大于 B 到终点的最短距离,则可以从 A 通往 B 处,问满 ...

  9. ACM: HDU 1874 畅通工程续-Dijkstra算法

    HDU 1874 畅通工程续 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Desc ...

随机推荐

  1. YTU 3002: 出栈顺序(栈和队列)

    3002: 出栈顺序(栈和队列) 时间限制: 1 Sec  内存限制: 128 MB 提交: 80  解决: 20 题目描述 给出一个入栈序列,和一个出栈序列,判断该出栈序列是否正确. 输入 输入包含 ...

  2. LinkedList的实现原理

    转载:http://wiki.jikexueyuan.com/project/java-collection/linkedlist.html 概述 LinkedList 和 ArrayList 一样, ...

  3. 从客户端中检测到有潜在危险的Request.Form 值

    今天往MVC中加入了一个富文本编辑框,在提交信息的时候报了如下的错误:从客户端(Content="<EM ><STRONG ><U >这是测试这...&q ...

  4. 解决浏览器使用<pre></pre>时不换行

    <!-- 解决火狐浏览器中pre标签不换行 --> <style type="text/css"> pre { white-space: pre-wrap; ...

  5. 内存恶鬼drawRect

    标题有点吓人,但是对于drawRect的评价倒是一点都不过分.在平日的开发中,随意覆盖drawRect方法,稍有不慎就会让你的程序内存暴增.下面我们来看一个例子. 去年的某天午后,北京的雾霾依旧像现在 ...

  6. 2016年10月14日 星期五 --出埃及记 Exodus 18:25

    2016年10月14日 星期五 --出埃及记 Exodus 18:25 He chose capable men from all Israel and made them leaders of th ...

  7. [kipmi0]进程导致系统负载高

    最近一个用户这边服务器运行四五天就会出现服务器负载很高的情况,原本正常是0.3~0.5左右  不正常的时候会达到3,重启机器就正常,开始以为是程序问题,后来在观察的时候把程序给杀掉了 然后重启,结果负 ...

  8. Linux源代码分析工具链

    前言 看源代码是一个程序员必须经历的事情,也是可以提升能力的一个捷径.个人认为: 要完全掌握一个软件的方法只有阅读源码. 在Windows下有sourceinsight这个源码阅读软件(虽然我没用过, ...

  9. linux mv命令

    mv命令是move的缩写,可以用来移动文件或者将文件改名(move (rename) files),是Linux系统下常用的命令,经常用来备份文件或者目录. 1.命令格式: mv [选项] 源文件或目 ...

  10. linux下vim命令详解

    高级一些的编辑器,都会包含宏功能,vim当然不能缺少了,在vim中使用宏是非常方便的::qx     开始记录宏,并将结果存入寄存器xq     退出记录模式@x     播放记录在x寄存器中的宏命令 ...