USACO 4.1.3
Fence Loops解题报告
题意:
题目的意思就是,给很多边,边的信息包括,ID编号,长度,两端分别与哪些边相邻。
然后求一个最小的回路。
思路:
1. 求最小回路,只需枚举每条边。对于一条边,去掉这条边后,求出这条边两个端点间的最短路径,就可以算出关于这条边的最小回路。最后比较得到最小的回路就是所求的。
2. 求最短路径可以用dijkstra,但是这道题的存储方式是边,而且不是给的边的端点来表示边,而是直接给的边的ID。这样给题目带来不少麻烦。首先能想到的是,转换成用点表示的图。感觉可能很麻烦于是,我采用了直接用边做 dijkstra的方法
用边存储的dijkstra算法细节:
我的边的类:
class fence
{
public:
intid; //ID
intlength; //长度
intnl,nr; //左、右边集数
intSL[8],SR[8]; //边集具体内容
intdis; //距离起始端点距离
};
当然思想是一样的,都是用dijkstra的贪心思想。
用一个优先队列priority_queue 存储可以走的边,,排序方法是,当前边距离起始端点的距离。
和传统的dijkstra不一样的就是,直接存储的可走的边,而不是可达的点,而且此边的dis一定是正确的。为什么?两条边进入同一点,但由于路径不同,两条边的dis可能不一样,但是由于采用的是优先队列,较远的到达这点的边永远是在后面的,所以不影响正确结果。可以这样想,每次更新队列,可达的下一个最近的点,是依托在一条边上的,而边在优先队列内的顺序是由距离dis决定的。所以可以保证队首的边,一定是到达下一个最近的点的边。
开始的时候,选择当前枚举的边的一端作为起始点(我是分为SL左边集,和SR右边集,我选的是SL左边集作为起始端),连着这一端的边集合,放到队列中,记录每条边到起始端的距离,当然第一批放进去的就是,边自身的长度了。然后就是不断从队列中取出首元素,计算他的另一端有哪些边,如果不在队列中,计算下这条边的dis,然后放进去。
找到路径的标志是,取出的队首元素,是当前所枚举的边的另一侧的边集合中的一个。在我的算法中,由于开始用从左边集SL中开始的,所以结束就是在SR中。