NOIP 模拟七 (回家,寿司)
T2 回家(0pts):
分析: 首先是对题目中关键点的理解,显然本题核心所在就在于求解无向图的“必经之路”(也就是说所有有效路径都必须经过的点)
这很显然是求无向图的割点,思路显然是利用Tarjan算法求解(考场上也确实有人这么做)
然而这道题有一个隐秘信息是此割点必须位于从学校(1号点)到家(n号点)的路径上(0pts警告)
那么现在问题就是如何确定割点所连路径经过1号点和n号点,显然我们要对Tarjan进行修改
我们可以将当前的问题视作有两个变量(1号点位置和n号点位置),需要通过定量(割点位置)来衡量这些量间的相互关系
一个很显然的思路是将其中一个变量“定下来”,也就是说如果我们以1号点为根节点进行Tarjan,那么所有割点经过的路径上必然存在1号点
此时我们就完成了对问题的简化,我们只需要判断割点所经过的路径上是否存在n点即可
考虑Tarjan算法的运行原理,如果节点a的时间戳大于节点b的时间戳,那么必定存在一条路径由b通向a
如果同时b节点是割点,那么b必定将1号点与a点分置两侧,此时b点就是“必经点”
代码:
1 void tarjan(int x) 2 { 3 int son=0; 4 dfn[x]=low[x]=++num; 5 for(register int i=fr[x];i;i=mo[i].pr) 6 { 7 register int y=mo[i].to; 8 if(!dfn[y]) 9 { 10 tarjan(y); 11 low[x]=min(low[x],low[y]); 12 if(low[y]>=dfn[x]&&dfn[y]<=dfn[n]) 13 { 14 son++; 15 if(x!=1||son>1) cut[x]=1; 16 } 17 } 18 else low[x]=min(low[x],dfn[y]); 19 } 20 } 21 22 来自starsing
总结:事实上判断n节点是否在割点路径上的方法很多(利用n点极大性通过数值判断(LYM),传递连通性(LRX)等)(当然个人还是认为上述代码思路最为简洁)
然而最为重要的还是对于问题的分析思路以及策略
T2考试及调试过程中出现的问题:1>对于Tarjan模板不熟系导致考场直接暴毙,应该去复习之前一些最基础的模板类
2>对于重边的处理,如果在建边时枚举判断来删除重边 时间复杂度会大大提升,这种情况下可以应用一个小技巧:成对变换(利用异或运算进行反向建边)
在建边时忽略重边,在使用时通过异或运算剔除重边极大降低了时间复杂度(对于自环在建边时若x==y,continue掉就行)
T3 寿司(5pts):
分析:首先先说一下直观思考:断环为链(大多数环上问题都可以转换为链上问题)
那么进行对于问题的分析(其实你发现想对于其他竞赛题,信息竞赛的题干十分冗杂,因此在拿到一个问题后首先要做的就是分析简化问题而不是去想做法)
这个问题很显然是对于n个长度为len区间(断环为链)你需要通过交换1和0使得1与1,0与0完全相接,你需要找出在这n个区间中满足条件的最小交换次数
如果盲目交换很显然会暴毙,也就是说我们对于问题本质的分析还不够,我们需要使0与0,1与1完全相接,由于其本体呈环状,这不就是说只要把1全移到两侧或把0全移到两侧就满足条件吗?
(交换0与交换1等效,这里默认以1为中心)很容易想到的一件事是对于1其左移或右移的次数至于其左右0的个数有关
那么通过预处理前缀和,我们可以以O(1)的复杂度计算任意1左移或右移的代价,考虑数据范围极限复杂度是O(nlogn)
而枚举每个区间的复杂度为O(n),这也就是说我们计算每个区间最小值的复杂度必须为O(1)或O(logn)
其实很容易想到对于每个区间,其最小值关于选定的分界点呈单峰函数,那么O(logn)的计算方式显而易见:三分法求单峰函数极值(这里不做赘述)
这里主要讲O(1)计算方法,其实我们很容易发现在区间右移的过程中每次区间的变化只是左右端0,1的变化
这启发我们可以同过递推,也就是观察变化量来寻找关系来推出区间最小值(这里实在懒得写了,请自己考虑0,1变化后对于区间最小值的影响)
现在问题只剩下分界点的选择了,也就是最优性问题,一个很常见(清奇)的思路是最优点可以选取区间中点,似乎毫无道理,然而在区间右移过程中实际上会枚举到所有决策点
此时必然包含最有决策点,最终只要统计最小值即可。最终总时间复杂度O(Tn)
总结:对问题进行简化的思想,一些常规思路(断环为链),以及对于变量的应用(递推)
另外,本题最后最优性枚举的思想应用其实远不至于此,对于很多DP最优性问题同样适用,可以极大降低问题复杂程度(分解点选取,DP方程参数等),可以参考宝藏(NOIP2017提高组)一题状态转移方程的设计与思想