Dijkstra算法

【最短路径问题】
对在权图G=(V,E),从一个源点s到汇点t 有很多路径,其中路径上权和最少的路径,称从s 到t的最短路径。
【三角形定理&松弛】
我们知道三角形的特性:任意两边之和大于第三边
因此,在求解过程中,若对于顶点x和顶点y不符合该特性,即可对它们进行“松弛”。

//设dis[x]为源点s到顶点x的最短距离

// adj[x][y]为顶点x、y之间的距离

dis[y]=min(dis[y],dis[x]+adj[x][y]);

【Dijkstra算法的思想】
(1)将G中顶点分成两个集合A、B,A集合中由已经求 最短路径的顶点组成,B集合是其它顶点。开始时A中 只有一个点s
(2)从B集合中取一个当前最短的顶点v
(3)把v加入A集合,并对v相连的顶点试做“ 松弛
(4)如果|A|=|V|,结束。否则转(2)
我们可以发现,Dijkstra算法与最小生成树问题中的Prim算法有相似之处。
【伪代码实现】

SP_Dijkstra(G, s) //求单源s到其它点的最短距离
for i=1 to n do
dis[i] ← ∞ //初始化每点到s距离
inA[i] ← false //设顶点不在A中
dis[s] ← 0 //将dis[s]设为0,准备取出
for i=1 to n do
v ← get-min() //取dis[?]中最小的值c和顶点v,
inA[ v ] ← true //v放入A中
updata( v ) //检查(v,B),松弛dis[? ]

【时空复杂度】
Dijkstra算法的时间复杂度是O(|V|^2),空间复杂度是O(|V|)。
================================================
【例题:cooking】

Bessie喜欢为在外面的奶牛做晚餐,Bessie按响铃给他们一个信号叫他们进来就可以了。
晚餐将在T (1 <= T <= 1,000,000)毫秒完成,而且Bessie强调那些想吃她晚餐的奶牛必须准时到。
这些牛在F (1 <= F <= 500)各不同的草地标号为1~F用P(1 <= P <= 10,000)个双向的小路连接。Bessie在第1个草地, 给出一头牛走每一条小路所用的时间,问多少个草地上的奶牛可以在T毫秒内到Bessie 所在的草地,假设多头牛可以共享一条路。

PROBLEM NAME: cooking

INPUT FORMAT:
第一行:三个整数用空格隔开,T,F,P
第2~P+1 行,每行表示在两个草地间的一条路,给出三个用空格隔开的整数,分别表示,
这条路所连接的一个草地和另一个草地以及奶牛走这条路所需要的毫秒数(1..1,000,000)
SAMPLE INPUT (file cooking.in):
1000 5 6
1 2 300
2 4 200
3 4 600
3 4 800
5 3 100
2 5 650
INPUT DETAILS:
晚餐将在1000毫秒完成,有5块草地,用6条小路连接

OUTPUT FORMAT:
一行,可以在T毫秒内到达Bessie所在的位置草地的个数
SAMPLE OUTPUT (file cooking.out):
4
OUTPUT DETAILS:
在1,2,4,5号草地的奶牛可以在1000毫秒内到达Bessie所在的草地,而3号草地上的奶牛不可以


【题意分析】
给出F个顶点和P条边,构造无向图G,计算每个顶点到顶点1的最短路径,问有多少个顶点的最短路径≤T。
【解题思路】
这题主要是分别求F个顶点的最短路径,且1<=F<=500,可以用邻接矩阵储存图并用Dijkstra算法求解。
【时空复杂度】
时间主要花在最短路径上,采用Dijkstra算法求解的时间复杂度为O(N^2),最大为O(2.5*10^5),不超时。
【代码】

#include<cstdio>
#define min(x,y) (x<y?x:y)
const int SIZE=500+5;
const int oo=0x7ffffff;
int T,F,P,G[SIZE][SIZE],dis[SIZE];
bool visited[SIZE];
int get_min();
void update(int);
int main() {
freopen("cooking.in","r",stdin);
freopen("cooking.out","w",stdout);
scanf("%d%d%d",&T,&F,&P);
for(int i=0; i!=F+1; ++i)
for(int j=0; j!=F+1; ++j)
G[i][j]=oo;
for(int i=0; i!=P; ++i) {
int x,y,distance;
scanf("%d%d%d",&x,&y,&distance);
G[x][y]=min(G[x][y],distance);
G[y][x]=min(G[y][x],distance);
}
for(int i=0; i!=F+1; ++i) {
dis[i]=oo;
visited[i]=false;
}
dis[1]=0;
for(int i=0; i!=F+1; ++i) {
int v=get_min();
visited[v]=true;
update(v);
}
int ans=1;
for(int i=2;i!=F+1;++i)ans+=dis[i]<=T;
printf("%d\n",ans);
return 0;
}
int get_min() {
int minV=0;
for(int i=1; i!=F+1; ++i)
if(!visited[i])minV=dis[i]<dis[minV]?i:minV;
return minV;
}
void update(int v) {
for(int i=1; i!=F+1; ++i)
for(int j=1; j!=F+1; ++j)
dis[j]=min(dis[j],dis[i]+G[i][j]);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值