博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ3197:[SDOI2013]刺客信条——题解
阅读量:5775 次
发布时间:2019-06-18

本文共 4264 字,大约阅读时间需要 14 分钟。

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

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

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

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

参考:

多半是树哈希判同构了。

设$f[u][v]$表示$u$子树和$v$子树同构且同层的情况下$u$子树原标记变动成$v$子树的新标记需要的最少次数。

那么实际上就是枚举$u$和$v$的儿子子树互相匹配,用他们的$f$转移到$f[u][v]$上,很明显这是一个带权二分图匹配的过程,KM是一个很好的选择。

如果要是枚举根来做的话,复杂度就是$O(1331n^2)$过不了,当然如果你使用动态换根的话,虽然我没有想过,但是到目前位置,代码已经快200行了,如果再动态换根的话就要累死了(当然debug就更累了)。

我们有个很妙的性质:取这棵树的重心(如果有两个重心,则将两个重心之间的边上建这个点,取这个点)作为根。

因为我们有一个美妙的结论:两棵树同构,当且仅当以两棵树重心为根的树同构。

(其实我也不知道为什么233可能是此时同构的对是最多的吧……)

#include#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;typedef unsigned long long ll;const int M=12;const int N=705;const int B=6662333;const int INF=1e9;inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X;}int dis[M][M],wx[M],wy[M],match[M],sla[M];bool vx[M],vy[M];bool dfs2(int u,int n){ vx[u]=1; for(int v=1;v<=n;v++){ if(!vy[v]){ int w=wx[u]+wy[v]-dis[u][v]; if(!w){ vy[v]=1; if(!match[v]||dfs2(match[v],n)){ match[v]=u;return 1; } }else sla[v]=min(sla[v],w); } } return 0;}int KM(int n){ memset(wx,-127,sizeof(wx)); memset(wy,-127,sizeof(wy)); memset(match,0,sizeof(match)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) wx[i]=max(wx[i],dis[i][j]); for(int i=1;i<=n;i++){ memset(sla,127,sizeof(sla)); while(1){ memset(vx,0,sizeof(vx)); memset(vy,0,sizeof(vy)); if(dfs2(i,n))break; int minn=INF; for(int j=1;j<=n;j++) if(!vy[j])minn=min(minn,sla[j]); for(int j=1;j<=n;j++){ if(vx[j])wx[j]-=minn; if(vy[j])wy[j]+=minn; else sla[j]-=minn; } } } int ans=0; for(int i=1;i<=n;i++)if(dis[match[i]][i]!=-INF)ans-=dis[match[i]][i]; return ans;}struct node{ int to,nxt;}e[N*2];int n,cnt,head[N],fa[N],a[N],b[N],q[N],size[N],son[N],dep[N];ll h[N];inline void add(int u,int v){ e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;}int calcg(int st){ int r=0,g1,g2=0,maxn=n; q[++r]=st;fa[st]=0; for(int l=1;l<=r;l++){ int u=q[l];size[u]=1;son[u]=0; for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(v==fa[u])continue; fa[v]=u;q[++r]=v; } } for(int l=r;l>=1;l--){ int u=q[l],v=fa[u]; if(r-size[u]>son[u])son[u]=r-size[u]; if(son[u]
son[v])son[v]=size[u]; } if(!g2)return g1; for(int i=head[g1];i!=-1;i=e[i].nxt){ int v=e[i].to; if(v==g2){ e[i].to=++n;e[i^1].to=n; add(n,g1);add(n,g2); return n; } }}ll dfs1(int u){ ll num[N];int r=0; size[u]=1;h[u]=B; for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(v==fa[u])continue; fa[v]=u;dep[v]=dep[u]+1;num[++r]=dfs1(v);size[u]+=size[v]; } sort(num+1,num+r+1); for(int i=1;i<=r;i++)h[u]=h[u]*B+num[i]; return h[u]*=size[u];}int f[N][N],to1[N],to2[N];int find(int u1,int u2){ int idx1=0,idx2=0; memset(to1,0,sizeof(to1)); memset(to2,0,sizeof(to2)); for(int i=head[u1];i!=-1;i=e[i].nxt){ int v1=e[i].to;if(v1==fa[u1])continue; if(!to1[v1])to1[v1]=++idx1; for(int j=head[u2];j!=-1;j=e[j].nxt){ int v2=e[j].to;if(v2==fa[u2])continue; if(!to2[v2])to2[v2]=++idx2; //printf("1 %d %d %d\n",v1,v2,f[v1][v2]); dis[to1[v1]][to2[v2]]=-f[v1][v2]; } } return KM(idx1)+(a[u1]!=b[u2]);}int bfs(int s){ int r=0; q[++r]=s; for(int l=0;l<=r;l++){ int u=q[l]; for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(v==fa[u])continue; q[++r]=v; } } for(int i=r;i>=0;i--){ if(dep[q[i]]!=dep[q[r]]){ i++; for(int j=r;j>=i;j--) for(int k=r;k>=i;k--) if(h[q[j]]==h[q[k]]){ f[q[j]][q[k]]=find(q[j],q[k]); //printf("%d %d %d\n",q[j],q[k],f[q[j]][q[k]]); } r=i-1; } } return find(s,s);}int main(){ cnt=-1,memset(head,-1,sizeof(head)); n=read(); for(int i=1;i

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:+

+++++++++++++++++++++++++++++++++++++++++++

转载于:https://www.cnblogs.com/luyouqi233/p/9192742.html

你可能感兴趣的文章
(一)Builder(建造者)模式
查看>>
[转]基于NodeJS的14款Web框架
查看>>
IIS7/8下提示 HTTP 错误 404.13 - Not Found 请求筛选模块被配置为拒绝超过请求内容长度的请求...
查看>>
http返回状态码含义
查看>>
提高网站页面加载速度的方法
查看>>
分布式缓存的面试题2
查看>>
响应式网站对百度友好关键
查看>>
洛谷P2179 骑行川藏
查看>>
暑假周总结三
查看>>
debian stretch + kernel 4.4 固件发布(支持硬件加速),可安装kodi
查看>>
(十八)js控制台方法
查看>>
VB关键字总结
查看>>
虚拟机类加载机制
查看>>
android代码生成jar包并混淆
查看>>
Java基础2-基本语法
查看>>
SPI总线通信电路设计
查看>>
一个不错的vue项目
查看>>
屏蔽指定IP访问网站
查看>>
[leetcode] 237. Delete Node in a Linked List
查看>>
python学习 第一天
查看>>