【JZOJ3296】【BZOJ3197】【luoguP3296】刺客信条

故事背景设定在1486年的意大利,主人公Ezio成为刺客大师,寻找刺客墓穴中的线索。问题转化为找到最少改动刺客标记次数,使树结构与封印密码匹配。通过分析,利用树的重心、哈希和二分图权值最小匹配(ZKW费用流)解决此问题。代码实现中提到哈希计算需注意模数选取。
摘要由CSDN通过智能技术生成

description

故事发生在1486 年的意大利,Ezio 原本只是一个文艺复兴时期的贵族,后来因为家族成员受到圣殿骑士的杀害,决心成为一名刺客。最终,凭借着他的努力和出众的天赋,成为了杰出的刺客大师,他不仅是个身手敏捷的武林高手,飞檐走壁擅长各种暗杀术。刺客组织在他的带领下,为被剥削的平民声张正义,赶跑了原本统治意大利的圣殿骑士首领-教皇亚历山大六世。在他的一生中,经历了无数次惊心动魄、扣人心弦的探险和刺杀。

曾经有一次,为了寻找Altair 留下的线索和装备,Ezio 在佛罗伦萨中的刺客墓穴进行探索。这个刺客墓穴中有许多密室,且任何两个密室之间只存在一条唯一的路径。这些密室里都有一个刺客标记,他可以启动或者关闭该刺客标记。为了打开储存着线索和装备的储藏室,Ezio 必须操作刺客标记来揭开古老的封印。要想解开这个封印,他需要通过改变某些刺客标记的启动情况,使得所有刺客标记与封印密码“看起来一样”。在这里,“看起来一样”

的定义是:存在一种“标记”密室与“密码”密室之间一一对应的关系,使得密室间的连接情况和启动情况相同(提示中有更详细解释)。幸运的是,在Ezio 来到刺客墓穴之前,在Da Vinci 的帮助下,Ezio 已经得知了打开储藏室所需要的密码。

而你的任务则是帮助Ezio 找出达成目标所需要最少的改动标记次数。


analysis

  • 就冲这题面肛整天都值得

  • 考虑先找出树的重心,这个 D P DP DP应该没人不会

  • 用哈希把树给搞一下,然后可以直接通过查询哈希值是否相等判断树是否同构

  • 预处理一下重心为根的树,然后从树上任意一点为根开始遍历整棵树,从下往上一层层 D P DP DP

  • f [ i ] [ j ] f[i][j] f[i][j]表示任意点为根的树中 i i i号点、重心为根的树中 j j j号点的最小代价值

  • 叶子结点的 f f f当然是它和目标状态是否相同,从叶子结点向上回溯

  • 类似树形 D P DP DP,对于一个节点的儿子中同构的儿子,让它们两两配对,使代价越小越好

  • 不就是二分图权值最小匹配,直接上 z k w zkw zkw费用流跑就好了

  • S , T S,T S,T连出流量 1 1 1费用 0 0 0的边,两棵树两两儿子节点间连流量 1 1 1费用 f [ 儿 子 1 ] [ 儿 子 2 ] f[儿子1][儿子2] f[1][2]的边

  • 然后就没了

  • 该代码成功垫底本子 O J OJ OJ

  • 其实我打的哈希有点假,取错模数会 G G GG GG,应该打双哈希,只不过我很懒……


code

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#define MAXN 1405
#define mod 19260817
#define INF 1000000007
#define ll long long
#define fo(i,a,b) for (ll i=a;i<=b;++i)
#define fd(i,a,b) for (ll i=a;i>=b;--i)
#define rep(i,a) for (ll i=last[a];i;i=next[i])
#define rep1(i,a) for (ll i=las[a];i;i=nxt[i])

using namespace std;

ll f[705][705],map1[705][705],map2[705][705];
ll last[MAXN],next[MAXN],tov[MAXN],cur[MAXN];
ll las[MAXN],nxt[MAXN],to[MAXN],len1[MAXN
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值