Bzoj3197: [Sdoi2013]assassin
题面
Sol
套路:找出重心,如果有两个就新建一个点
然后把这棵树hash一下
设\(f[i][j]\)表示第一颗树到\(i\)第二棵树到\(j\),子树\(i,j\)同构的付出的最小代价
转移:每次把这一层hash值相同的点做一边二分图权匹配(KM/费用流)就好了
一遍AC
# include <bits/stdc++.h>
# define IL inline
# define RG register
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
const int maxn(1005);
const int inf(1e9);
const ll seed1(9377);
const ll seed2(10007);
namespace MCMF{
int dis[maxn], pre1[maxn], pre2[maxn], vis[maxn], first[maxn], cnt, ans, s, t;
queue <int> q;
struct Edge{
int to, next, f, w;
} edge[maxn * maxn * 2];
IL void Init(RG int a, RG int b){
s = a, t = b, ans = cnt = 0;
for(RG int i = a; i <= b; ++i) first[i] = -1;
}
IL void Add(RG int u, RG int v, RG int f, RG int w){
edge[cnt] = (Edge){v, first[u], f, w}, first[u] = cnt++;
edge[cnt] = (Edge){u, first[v], 0, -w}, first[v] = cnt++;
}
IL int Aug(){
for(RG int i = s; i <= t; ++i) dis[i] = inf;
q.push(s), dis[s] = 0, vis[s] = 1;
while(!q.empty()){
RG int u = q.front(); q.pop();
for(RG int e = first[u]; e != -1; e = edge[e].next){
RG int v = edge[e].to;
if(edge[e].f && dis[v] > dis[u] + edge[e].w){
dis[v] = dis[u] + edge[e].w;
pre1[v] = e, pre2[v] = u;
if(!vis[v]) q.push(v), vis[v] = 1;
}
}
vis[u] = 0;
}
if(dis[t] == inf) return 0;
RG int ret = inf;
for(RG int p = t; p; p = pre2[p]) ret = min(ret, edge[pre1[p]].f);
ans += ret * dis[t];
for(RG int p = t; p; p = pre2[p])
edge[pre1[p]].f -= ret, edge[pre1[p] ^ 1].f += ret;
return 1;
}
IL int Calc(){
for(ans = 0; Aug(); );
return ans;
}
}
int cnt, first[maxn];
struct Edge{
int to, next;
} edge[maxn << 1];
namespace Hash{
struct Val{
unsigned long long f1, f2;
IL int operator ==(RG Val b) const{
return f1 == b.f1 && f2 == b.f2;
}
} v[maxn];
IL int Cmp(RG int a, RG int b){
return v[a].f1 != v[b].f1 ? v[a].f1 < v[b].f1 : v[a].f2 < v[b].f2;
}
int size[maxn];
IL void GetHash(RG int u, RG int ff){
vector <int> son; son.clear(), size[u] = 1;
for(RG int e = first[u]; e != -1; e = edge[e].next){
RG int v = edge[e].to;
if(v != ff){
GetHash(v, u);
size[u] += size[v], son.push_back(v);
}
}
sort(son.begin(), son.end(), Cmp);
for(RG int i = 0, l = son.size(); i < l; ++i){
v[u].f1 = v[u].f1 * seed1 + v[son[i]].f1 * seed1 + v[son[i]].f2 * seed2;
v[u].f2 = v[u].f2 * seed2 + v[son[i]].f1 * seed2 + v[son[i]].f2 * seed1;
}
v[u].f1 = v[u].f1 * seed1 + size[u];
v[u].f2 = v[u].f2 * seed2 + size[u];
}
};
int n, size[maxn], c1[maxn], c2[maxn], rt, tmp;
int f[maxn][maxn];
IL void Add(RG int u, RG int v){
edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++;
}
IL void GetRoot(RG int u){
size[u] = 1; RG int mx = 0;
for(RG int e = first[u]; e != -1; e = edge[e].next){
RG int v = edge[e].to;
if(!size[v]){
GetRoot(v);
size[u] += size[v];
mx = max(mx, size[v]);
}
}
mx = max(mx, n - size[u]);
if((mx << 1) <= n){
if(!rt) rt = u;
else tmp = u;
}
}
IL void Solve(RG int u1, RG int u2, RG int ff1, RG int ff2){
f[u1][u2] = c1[u1] != c2[u2];
vector <int> son1, son2; son1.clear(), son2.clear();
for(RG int e = first[u1]; e != -1; e = edge[e].next)
if(edge[e].to != ff1) son1.push_back(edge[e].to);
for(RG int e = first[u2]; e != -1; e = edge[e].next)
if(edge[e].to != ff2) son2.push_back(edge[e].to);
RG int l1 = son1.size(), l2 = son2.size(), s = 0, t = l1 + l2 + 1;
for(RG int i = 0; i < l1; ++i)
for(RG int j = 0; j < l2; ++j)
if(Hash::v[son1[i]] == Hash::v[son2[j]]) Solve(son1[i], son2[j], u1, u2);
MCMF::Init(0, t);
for(RG int i = 0; i < l1; ++i)
for(RG int j = 0; j < l2; ++j)
if(Hash::v[son1[i]] == Hash::v[son2[j]]) MCMF::Add(i + 1, j + 1 + l1, 1, f[son1[i]][son2[j]]);
for(RG int i = 0; i < l1; ++i) MCMF::Add(s, i + 1, 1, 0);
for(RG int i = 0; i < l2; ++i) MCMF::Add(i + 1 + l1, t, 1, 0);
RG int ret = MCMF::Calc();
f[u1][u2] += ret;
}
int main(){
n = Input();
for(RG int i = 1; i <= n + 1; ++i) first[i] = -1;
for(RG int i = 1; i < n; ++i){
RG int u = Input(), v = Input();
Add(u, v), Add(v, u);
}
for(RG int i = 1; i <= n; ++i) c1[i] = Input();
for(RG int i = 1; i <= n; ++i) c2[i] = Input();
GetRoot(1);
if(tmp){
for(RG int e = first[rt]; e != -1; e = edge[e].next)
if(edge[e].to == tmp) edge[e].to = n + 1;
for(RG int e = first[tmp]; e != -1; e = edge[e].next)
if(edge[e].to == rt) edge[e].to = n + 1;
Add(n + 1, rt), Add(n + 1, tmp), rt = n + 1;
}
Hash::GetHash(rt, 0);
Solve(rt, rt, 0, 0);
printf("%d\n", f[rt][rt]);
return 0;
}
Bzoj3197: [Sdoi2013]assassin的更多相关文章
- 【BZOJ3197】[Sdoi2013]assassin 树同构+动态规划+KM
[BZOJ3197][Sdoi2013]assassin Description Input Output Sample Input 4 1 2 2 3 3 4 0 0 1 1 1 0 0 0 Sam ...
- [BZOJ3197][SDOI2013]刺客信条assassin
bzoj luogu Description 故事发生在1486 年的意大利,Ezio原本只是一个文艺复兴时期的贵族,后来因为家族成员受到圣殿骑士的杀害,决心成为一名刺客.最终,凭借着他的努力和出众的 ...
- bzoj 3197 [Sdoi2013]assassin(Hash+DP+KM)
Description Input Output Sample Input 4 1 2 2 3 3 4 0 0 1 1 1 0 0 0 Sample Output 1 HINT [思路] Hash,D ...
- BZOJ 3197: [Sdoi2013]assassin 树形DP + 最小费用流 + 树的同构
Description Input Output 其实就是给出两颗树,求一种两种树同构的方式,使得不同颜色个数最少$.$树的重新构建,其实就是指定不同的点为根节点$.$ 好在树的重心有一个重要的性质: ...
- BZOJ 3197 [Sdoi2013]assassin
题解: 树上Hash 首先重心在边上就把边分裂 以重心为根建树,这样两个根一定对应 然后f[i][j]表示i匹配另一棵的j节点的最小代价 把他们的儿子摘出来做最小权匹配即可 #include<i ...
- 字符串Hash/树Hash学习笔记
哈希 Tags:字符串 作业部落 评论地址 一.概述 百度百科: 散列表(Hash table/哈希表),是根据关键码值(Key value)而直接进行访问的数据结构. 哈希表常用于比较两个字符串是否 ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- Bzoj3197/洛谷3296 [SDOI2013]刺客信条assassin(树的重心+树Hash+树形DP+KM)
题面 Bzoj 洛谷 题解 (除了代码均摘自喻队的博客,可是他退役了) 首先固定一棵树,枚举另一棵树,显然另一棵树只有与这棵树同构才有可能产生贡献 如果固定的树以重心为根,那么另一棵树最多就只有重心为 ...
- 【BZOJ3197】[SDOI2013]刺客信条
[BZOJ3197][SDOI2013]刺客信条 题面 bzoj 洛谷 题解 关于树的同构,有一个非常好的性质: 把树的重心抠出来,那么会出现两种情况: 1.有一个重心,那么我们直接把这个重心作为树的 ...
随机推荐
- 给 console 添加颜色
简评:使用 %c 声明可以给 console 的输出添加 CSS 样式,日志太多的话,给不同种类的日志设置不同的样式,可以极大的提升阅读体验. 什么是 %c %c: 标识将 CSS 样式应用于 %c ...
- 【ASP.NET Core MVC 入门须知】Net Core和Net Framework 的区别
1.简单介绍 从上面图中我们可以看到.net 主要分为三个部分 .net FrameWork,.net Core ,Xamarin XAMARIN 主要用来构建APP的主要用的是C#语言 .NE ...
- 【python】10分钟教你用python打造贪吃蛇超详细教程
10分钟教你用python打造贪吃蛇超详细教程 在家闲着没妹子约, 刚好最近又学了一下python,听说pygame挺好玩的.今天就在家研究一下, 弄了个贪吃蛇出来.希望大家喜欢. 先看程序效果: 0 ...
- Vue 不睡觉教程1-从最土开始
目标最近在学习vue的过程中发现网上的vue教程总有些不同的问题,有的教程上来只说语法,有的教程上来就用vue-cli来建项目,但是vue-cli是整合了webpack等多个插件的工具,不利于我们学习 ...
- Log中关于zVideoApp与zChatApp之间的消息传递可以搜索以下字符串
[CSSBConfIPCAgent::OnMessageReceived] (这是zVideoApp端的) 和 [CSSBPTIPCListener::OnMessageReceived] ...
- Python turtle库学习笔记
1.简介 Python的turtle库的易操作,对初学者十分友好.对于初学者来说,刚学编程没多久可以写出许多有趣的可视化东西,这是对学习编程极大的鼓舞,可以树立对编程学习的信心.当然turtle本身也 ...
- FJWC2019 最短路
题目描述 有一张无向图,开始的时候所有边权为1,所有点没有权值,现在给定一个整数k,表示可以将k个点的点权设置为1,求点0到n-1的最短路最长是多少 Solution 网络流好题[然而本蒟蒻还是不会] ...
- tp5.0 根据经纬度 获取附近信息
自己备注一下 /* *参数说明: *$lng 经度 *$lat 纬度 *$distance 周边半径 默认是500米(0.5Km) */ public function returnSquarePoi ...
- HttpClient 工具类
package com.sys.utils; import java.io.IOException; import java.net.URI; import java.util.ArrayList; ...
- springboot项目:项目部署
第一步:打开终端,进入项目根目录 输入命令: cd /Users/liuxiaoming/Documents/software/ideawork/sell/ 第二步:对项目进行打包编译跳过测试: m ...