HDU-1142 A Walk Through the Fores
题目大意:给你一个无向图,从1号点到2号点有多少种 “不绕远” 的方法
(这个“不绕远”很坑,意思是你接下来的每一步都要更接近终点,而不是寻找最短路)
要想知道下一步有没有绕远,就要知道每个点到终点的距离,这个距离一定是最短的,无向图,单源最短路,自然想到用Dijstra,扫一遍最短路,然后再用DFS去求路径个数。
Dijstra算法:从终点开始,扫一遍每一个相邻的点,把到终点的最小距离存进去,然后塞进队列或者栈里面(稍后说为什么用队列)然后从容器里面取出来一个点,标记这个点防止循环,把这个点相邻的再扫一遍,更新距离,存入容器,直到容器为空,扫过每一个点,输出起点的距离,程序结束。
分治思想,想知道起点到终点的最小距离,就要知道起点附近这一圈的点到终点的最短距离,而要知道这一圈,就要知道再下一圈,最终到达终点附近的一圈点,他们的最短就是到终点的距离。
PS:一遍过真的是谢天谢地
!!优先队列优化!!优先队列是一个有排序功能的队列,这样可以使得被取出来的元素是最小的,优先扫最短的路,超大数据情况下,可减少时间复杂度,小范围数据效果不大。
DFS:递归扫描,判断的条件是两点连通且距离更小,路径数增加的条件是寻找到终点
if(src == 2) //搜索到终点,有一条路
{
return 1;
}
if(way[src] != -1) //当前点已经被搜索过一次了
{
return way[src];
}
全部代码——>
#include<iostream>
#include<algorithm>
#include<queue>
#include<string.h>
using namespace std;
#define INF 0x3fffffff //理论上的无穷大,表示两个点不连通
#define maxn 1005
int load[maxn][maxn]; //无向图,例:load[2][3] = 4; 表示点2到点3之间的距离是4;
int longload[maxn]; //到终点的距离
bool camp[maxn]; //标记是否已经被浏览
int way[maxn]; //这个点有几条路,初始化为负可同时作为标记组使用
int a,b;
int DFS(int src) //src路径起点
{
if(way[src] != -1) //当前点已经被搜索过一次了
{
return way[src];
}
if(src == 2) //搜索到终点,有一条路
{
return 1;
}
way[src] = 0; //标记
for(int i = 1 ; i <= a ; i++)
{
if(longload[i] < longload[src] && load[i][src] != INF) //下一步能走且可以走得更远
{
way[src] = way[src] + DFS(i);
}
}
return way[src]; //搜索完成,返回结果
}
typedef struct node // a 点的编号,b 到终点的距离
{
int x , v;
node(int a , int b)
{
x = a; v = b;
}
friend bool operator < (node a,node b) //友元函数,重载比较运算符,使用自定义类型的数据创建优先队列必须重载此运算符
{
return a.v > b.v;
}
}creatnode;
int main()
{
while(1)
{
int x,y,z;
cin >> a; if(a == 0) break;
cin >> b;
priority_queue<creatnode> Map; //创建优先队列
for(int i = 1 ; i <= a ; i++)
{
fill(load[i] , load[i] + maxn , INF); //函数值替换,初始化
camp[i] = false; //判定数组初始化
longload[i] = INF; //存储距离
load[i][i] = 0;
}
for(int i = 1 ; i <= b ; i++) //建图
{
cin >> x >> y >> z;
load[x][y] = load[y][x] = z;
}
longload[2] = 0; //终点到终点距离是0
creatnode path(2,0);
Map.push(path); //将起点作为第一个点入队
//-----------------Dijkstra------------------//
while(!Map.empty())
{
creatnode Q = Map.top(); Map.pop(); //取出一个点
if(camp[Q.x] == true) continue; //标记
camp[Q.x] = true;
for(int i = 1 ; i <= a ; i++)
{
if(camp[i] == false && longload[i] > Q.v + load[i][Q.x]) //没有被遍历过且距离目标点的距离可以更小
{
longload[i] = Q.v + load[i][Q.x];
creatnode path(i , longload[i]);
Map.push(path); //符合条件,入队
}
}
}
//-------------------DFS---------------------//
memset(way , -1 , sizeof(way));
cout << DFS(1) << endl;
}
return 0;
}
Comments 1 条评论
博主 木头罗
6