xtuoj 环
题目
思路
题目是一个环,且从1号节点出发,我们可以顺时针也可以逆时针走,所以我们可以定义两个数组,一个数组表示从1号节点出发顺时针走经过的边权之和,另外一个数组表示从1号节点出发逆时针走经过的边权之和。
注意这里不需要从1号点出发最后还要回到1号点,所以我们完全可以删掉一条边,比如说w[i]。
这里有两种策略,一种是顺时针走到某点后,然后再逆时针回到1号节点,再接着走完剩下的节点;另一种策略是逆时针走到某点后,顺时针回到1号节点,再走完剩下的节点;只有这两种情况才有可能是最短的,其实也挺好理解的,最短的肯定是要么在某条边走一次,要么走两次,走两次是为了转向,其实是避开边权较大的那些边,同一条边走三次其实就相当于走了一次,那么多的那两次其实不能起到什么作用,我们的目的是以最小的边权代价覆盖所有的节点,你走一次可以覆盖两个节点,同一条边走三次也是覆盖两个节点,而且边权代价变大了,其他的同理,那你可能问为什么在同一条边走一次就能覆盖两个节点,那你为什么还有的边要走两次,同一条边走两次不也是覆盖两个节点吗,对的,覆盖的节点数是相同的,但是有可能继续走下去总的边权会变得很大,所以我们选择走两次,这样我们可以通过转向继续走完的方式覆盖到所以节点。
这里的w[i]表示的是第i个节点与第i+1个节点之间的边权,但是w[n]表示的是第n个节点与第一个节点之间的边权,因为要构成一个环。pref[i]表示的是前缀和数组,pref[i]=w[1]+w[2]+...+w[i],也就是前i条边的和,相当于从1号节点顺时针到i+1号节点经过的边权之和;suf[i]表示的是后缀和数组,suf[i]=w[i]+w[i+1]+...+w[n],相当于从1号节点逆时针i号节点所经过的边权之和。
首先for (int i = 1; i <= n; i++)相当于在枚举要删