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