这道题目其实就是上面一道“超级英雄”
这里将属性作为左部,装备作为右部就好了
其实我最开始是没有想到的,因为我一直在想把某一个对象作为二分图的节点
这道题目就启发我们,其实不是非要把一个对象作为二分图的节点的,我们还可以把两个对象分别作为二分图的左右部来考虑(转换对象法)
另外这道题目的 N N N非常大,我们需要改善一下匈牙利算法,就是将 v i s vis vis数组改成 i n t int int类型,然后在每次dfs的时候多加一个参数 t t t,表示这是第几次dfs,然后在dfs里面判断 v i s vis vis是否等于 t t t即可,这样就可以省去for循环的第一句memset了(注意dfs过程中 v i s vis vis不是加一,而是直接令成 t t t)
然后时间复杂度就正确了,可以从交错树的角度分析
注意交错树每一层的节点的属性都是相同的(指是左部节点还是右部节点),而且对于右部节点的层,每个节点只有唯一一个儿子,也就是说交错树的规模是左部节点的两倍,于是我们分析左部节点就好了,由于有 v i s vis vis标记,所以交错树的规模最多为 10000 10000 10000,而最多寻找 10000 10000 10000次增广路,于是时间复杂度就正确了
另外还有并查集解法,复习的时候做一下
思路正确性:对于没有环的连通块,我们任选 p − 1 p-1 p−1个点,相当于任选一个点让其不能被选,将这个点作为树根,不难发现可以找到一种合法的分配方案;若连通块有环,可以将其看做基环树再加上若干条边,显然可以找到一种合法的分配方案;而每次合并让更大的点当根也是比较显然的贪心
update 2024.5.13
并查集做法的思路是对的,但是合并的时候代码是错的
hack数据:
3
1 2
1 2
2 3
错误原因也比较显然,就不赘述了
正确做法应该是记录点数和边数,只要边数不少于点数,那么就说明有环(注意这是一个连通集,没有环当且仅当边数为点数减一)
这个思路的来源就是转换对象法,将属性作为考虑对象,然后尝试转化为图论,由于只给了两个属性值,就相当于告诉了边的起点和终点了(要对 2 2 2这个数字敏感)
这题的并查集也算个经典模型吧,相当于把每条边要么分给其起点,要么分给其终点,只能分给一个点