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],len2[MAXN];
ll g1[MAXN],g2[MAXN],depth[MAXN];
ll hash[MAXN],size[MAXN];
bool bz[MAXN];
ll n,tot,total,tmp,root,ans=INF,S,T,answer;inline ll read()
{ll x=0,f=1;char ch=getchar();while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;
}
inline bool cmp(ll x,ll y)
{return hash[x]<hash[y];
}
inline void link(ll x,ll y)
{next[++tot]=last[x],last[x]=tot,tov[tot]=y;
}
inline void find_root(ll x)
{ll mx=0;size[x]=1,bz[x]=0;rep(i,x)if (bz[tov[i]]){find_root(tov[i]);size[x]+=size[tov[i]];mx=max(mx,size[tov[i]]);}mx=max(mx,n-size[x]);if (mx<tmp)tmp=mx,root=x;
}
inline void dfs1(ll x,ll y)
{hash[x]=100007;rep(i,x)if (tov[i]!=y){dfs1(tov[i],x);map1[x][++map1[x][0]]=tov[i];}sort(map1[x]+1,map1[x]+map1[x][0]+1,cmp);fo(i,1,map1[x][0])hash[x]=((hash[x]*mod)*hash[map1[x][i]])%INF;
}
inline void dfs2(ll x,ll y)
{hash[x]=100007,size[x]=1;rep(i,x)if (tov[i]!=y){dfs2(tov[i],x),size[x]+=size[tov[i]];map2[x][++map2[x][0]]=tov[i];}sort(map2[x]+1,map2[x]+map2[x][0]+1,cmp);fo(i,1,map2[x][0])hash[x]=((hash[x]*mod)*hash[map2[x][i]])%INF;
}
inline void link_edge(ll x,ll y,ll z1,ll z2)
{nxt[++total]=las[x],las[x]=total,to[total]=y,len1[total]=z1,len2[total]=z2;
}
inline bool spfa()
{memset(bz,1,sizeof(bz));memset(depth,127,sizeof(depth));deque<ll>q;q.push_front(T);depth[T]=bz[T]=0;while (!q.empty()){ll now=q.front();q.pop_front();rep1(i,now)if (len1[i^1] && depth[now]+len2[i^1]<depth[to[i]]){depth[to[i]]=depth[now]+len2[i^1];if (bz[to[i]]){bz[to[i]]=0;if (!q.empty() && depth[to[i]]<depth[q.front()])q.push_front(to[i]);else q.push_back(to[i]);}}bz[now]=1;}return depth[S]<INF;
}
inline ll dfs(ll x,ll flow)
{if (x==T){bz[T]=0;return flow;}ll used=0;bz[x]=0;for (ll i=cur[x];i;i=nxt[i]){cur[x]=i;if (len1[i] && bz[to[i]] && depth[to[i]]+len2[i]==depth[x]){ll tmp=dfs(to[i],min(len1[i],flow-used));if (tmp)answer+=len2[i]*tmp,len1[i]-=tmp,len1[i^1]+=tmp,used+=tmp;if (used==flow)break;}}return used;
}
inline ll zkwflow()
{ll flow=0;answer=0;while (spfa()){bz[T]=0;while (!bz[T]){memset(bz,1,sizeof(bz));memcpy(cur,las,sizeof(cur));flow+=dfs(S,INF);}}return flow;
}
inline ll dp(ll x,ll y)
{if (f[x][y]!=-1)return f[x][y];f[x][y]=g1[x]^g2[y];ll i=1;if (size[x]==1)return f[x][y];while (i<=map2[x][0]){ll j=i;while (j<map2[x][0] && hash[map2[x][i]]==hash[map2[x][j+1]])++j;fo(k,i,j)fo(l,i,j)dp(map2[x][k],map1[y][l]);S=2*n+1,T=2*n+2,total=1;memset(las,0,sizeof(las));memset(nxt,0,sizeof(nxt));memset(to,0,sizeof(to)),total=1;memset(len1,0,sizeof(len1));memset(len2,0,sizeof(len2));fo(k,i,j){link_edge(S,map2[x][k],1,0),link_edge(map2[x][k],S,0,0);link_edge(map1[y][k]+n,T,1,0),link_edge(T,map1[y][k]+n,0,0);fo(l,i,j){ll tmp=dp(map2[x][k],map1[y][l]);link_edge(map2[x][k],map1[y][l]+n,1,tmp);link_edge(map1[y][l]+n,map2[x][k],0,-tmp);}}zkwflow(),f[x][y]+=answer;i=j+1;}return f[x][y];
}
int main()
{n=read();fo(i,1,n-1){ll x=read(),y=read();link(x,y),link(y,x);}fo(i,1,n)g1[i]=read();fo(i,1,n)g2[i]=read();memset(bz,1,sizeof(bz)),tmp=INF,find_root(1);dfs1(root,0),tmp=hash[root];fo(i,1,n){memset(hash,0,sizeof(hash));memset(map2,0,sizeof(map2));dfs2(i,0);if (hash[i]==tmp){memset(f,-1,sizeof(f));ans=min(ans,dp(i,root));}}printf("%lld\n",ans);return 0;
}

【JZOJ3296】【BZOJ3197】【luoguP3296】刺客信条相关推荐

  1. [BZOJ3197][SDOI2013]刺客信条assassin

    bzoj luogu Description 故事发生在1486 年的意大利,Ezio原本只是一个文艺复兴时期的贵族,后来因为家族成员受到圣殿骑士的杀害,决心成为一名刺客.最终,凭借着他的努力和出众的 ...

  2. 【JZOJ3296】【SDOI2013】刺客信条(assassin)

    ╰( ̄▽ ̄)╭ Description 故事发生在1486 年的意大利,Ezio 原本只是一个文艺复兴时期的贵族,后来因为家族成员受到圣殿骑士的杀害,决心成为一名刺客.最终,凭借着他的努力和出众的天赋 ...

  3. BZOJ3197:[SDOI2013]刺客信条——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=3197 故事发生在1486 年的意大利,Ezio 原本只是一个文艺复兴时期的贵族,后来因为家族成员受 ...

  4. JZOJ3296. 【SDOI2013】刺客信条

    Description 故事发生在1486 年的意大利,Ezio 原本只是一个文艺复兴时期的贵族,后来因为家族成员受到圣殿骑士的杀害,决心成为一名刺客.最终,凭借着他的努力和出众的天赋,成为了杰出的刺 ...

  5. 刺客信条奥德赛无法加载库_点评刺客信条起源、奥德赛、英灵殿,哪个最好玩?...

    刺客信条起源 虽然大多数玩家一直诟病刺客信条系列的高重复性,在我看来,<刺客信条:起源>是育碧将刺客信条系列转向RPG的一大艺术品.这款游戏让我感到最惊讶的是世界氛围的营造.它的历史感以及 ...

  6. 《刺客信条:英灵殿》全面分析:浅谈公式化开放世界

    经过澳大利亚艺术家8个小时左右的艺术创作之后,育碧正式公布了刺客信条系列的最新一部作品--<刺客信条:英灵殿>的信息.受玩家万众瞩目的刺客信条系列终于在短暂的沉寂后,重新回到广大玩家们的视 ...

  7. 浅谈《刺客信条》的叙事:刺客和圣殿骑士的冲突与融合

    象征着<刺客信条>系列全新开端的<刺客信条3>如期而至.本作不仅将这个系列带到了一个全新的历史大背景中,也在玩法和故事上做出了许多的革新.而这些变化也使得<刺客信条3&g ...

  8. 刺客信条起源计算机内存不足,刺客信条起源需要什么配置能玩?最低/推荐配置需求介绍...

    刺客信条起源是育碧旗下刺客信条宇宙的最新一部作品,目前已经发售了一段时间了,近期steam冬季特卖又有一批新玩家入坑刺客信条起源来一起体验兄弟会的起源时刻,当然最关键的问题还是配置这一方面,有许多玩家 ...

  9. 刺客信条奥德赛ce修改技能点_刺客信条奥德赛特长加点

    刺客信条奥德赛特长加点,要根据自己的打法加点;猎人系加满弓箭射击还有第六感;战士系就加攻击力.防御力.血量就行;刺客系加英雄一击.刺杀加伤.背刺.急速刺杀.闪光弹;无论什么职业,基本上鹰眼都跟着升级加 ...

最新文章

  1. Count Complete Tree Nodes
  2. sql语句中开窗函数的使用
  3. [Hyper-V]在Windows 8.1 操作系统中启用Hyper-V功能
  4. spring BeanFactory概述
  5. 不同浏览器input file样式不一样
  6. 第三章 MongoDb Java应用 3.1
  7. Android学习笔记--Menu菜单的使用
  8. mysql 字段加减_MySQL数据库开发常见问题及优化(续)
  9. windows安装jdk与配置环境变量详解
  10. java反编译工具Java Decompiler
  11. dubbo源代码编译打包错误解决
  12. 软激活WIN7 Activation
  13. python网络爬虫网易云音乐guihub_Python开发的一个命令行的网易云音乐
  14. P7 黑客是如何发现女朋友出轨的,痛心的经历!
  15. EAS BOS 后台事务定义步骤
  16. iOS-纯代码编写本地音乐播放器AVAudioPlayer
  17. EFS加密文件重装系统无法打开图标带小锁显示绿色解密
  18. h5应用数据加密_在线视频加密用H5加密方案有哪些优点?
  19. arch模型的思路_ARCH模型是什么?
  20. 开发过程中 勘误表errata注意事项

热门文章

  1. #Python #字符画 #灰度图 使用Python绘制字符画及其原理
  2. 【bzoj 4976】宝石镶嵌(贪心、高位前缀和)
  3. ifree的爱情,是一条完美的九分裤
  4. pe联想服务器装系统教程视频,联想笔记本本地PE重装win7系统教程
  5. Python使用Turtle画玻利维亚国旗
  6. CVPR2021|通过多尺度特征融合提升深度估计模型精度
  7. Cesium地图暗色滤镜
  8. Windows10 升级 Windows11 教程 (无视TMP2.0)
  9. 天乩之白蛇传说 全 集 百 度 云 网 盘 资 源
  10. 使用profile的PASSWORD_VERIFY_FUNCTION参数实现自定义的密码验证规则