连续攻击游戏

这道题目其实就是上面一道“超级英雄”

这里将属性作为左部,装备作为右部就好了

其实我最开始是没有想到的,因为我一直在想把某一个对象作为二分图的节点

这道题目就启发我们,其实不是非要把一个对象作为二分图的节点的,我们还可以把两个对象分别作为二分图的左右部来考虑(转换对象法)

另外这道题目的\(N\)非常大,我们需要改善一下匈牙利算法,就是将\(vis\)数组改成\(int\)类型,然后在每次dfs的时候多加一个参数\(t\),表示这是第几次dfs,然后在dfs里面判断\(vis\)是否等于\(t\)即可,这样就可以省去for循环的第一句memset了(注意dfs过程中\(vis\)不是加一,而是直接令成\(t\)

然后时间复杂度就正确了,可以从交错树的角度分析

注意交错树每一层的节点的属性都是相同的(指是左部节点还是右部节点),而且对于右部节点的层,每个节点只有唯一一个儿子,也就是说交错树的规模是左部节点的两倍,于是我们分析左部节点就好了,由于有\(vis\)标记,所以交错树的规模最多为\(10000\),而最多寻找\(10000\)次增广路,于是时间复杂度就正确了

另外还有并查集解法,复习的时候做一下

思路正确性:对于没有环的连通块,我们任选\(p-1\)个点,相当于任选一个点让其不能被选,将这个点作为树根,不难发现可以找到一种合法的分配方案;若连通块有环,可以将其看做基环树再加上若干条边,显然可以找到一种合法的分配方案;而每次合并让更大的点当根也是比较显然的贪心

update 2024.5.13

并查集做法的思路是对的,但是合并的时候代码是错的

hack数据:

3
1 2
1 2
2 3

错误原因也比较显然,就不赘述了

正确做法应该是记录点数和边数,只要边数不少于点数,那么就说明有环(注意这是一个连通集,没有环当且仅当边数为点数减一)

这个思路的来源就是转换对象法,将属性作为考虑对象,然后尝试转化为图论,由于只给了个属性值,就相当于告诉了边的起点和终点了(要对\(2\)这个数字敏感)

这题的并查集也算个经典模型吧,相当于把每条边要么分给其起点,要么分给其终点,只能分给一个点

posted @ 2024-02-13 16:51  最爱丁珰  阅读(3)  评论(0编辑  收藏  举报