3197: [Sdoi2013]assassin

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 221 Solved: 113
[Submit][Status][Discuss]
Description

Input

Output

Sample Input

41 22 33 40 0 1 11 0 0 0

Sample Output

1

HINT

设f[i][j]f[i][j]表示i根j对应时的最小代价。这样树形dp就行了,从下往上更新。
在更新的时候,就相当于是这样一个问题,一些点可以和另一些点对应,每种对应都有相应的价值,问最小的价值。这很明显可以网络流。
如果x的一个儿子i可以和j对应,那么就在这两个点之间连一条(1,f[i][j])(1,f[i][j])的边,跑一边费用流,就是当前状态的答案。
怎样判断两个点能否对应呢??
可以hash这个树,hash相同的节点就是可以对应的节点。
还有一个问题:题中给的是一个无根树,如果随便选一个节点当根hash的话,呢么选的节点不同hash值会不一样。
考虑这是一棵树,那么就可以把树的重心当根,这样树就相当于被比较平均的分开了,再hash就没什么问题了。如果这个树有两个重心的话,就再新建一个节点,分别向两个重心连边,把这个点当成重心做就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
using namespace std;
#define LL unsigned int
#define p 233LL
#define D 1490
#define T 2*n+2
#define inf 707406378
const int N=1500;
const int M=500000;
bool use[N];
LL r[N],hash[N];
struct S{int st,en,va,co;}aa[M],bb[N];
int can,n,tot,siz[N],a[N],b[N],po[N],ne[N],point[N],next[M],l[N],dis[N],pre[N],s[N],root,o[5],f[N][N];
inline void add_1(int x,int y){
    ne[++tot]=po[x];po[x]=tot;
    bb[tot].st=x;bb[tot].en=y;
    ne[++tot]=po[y];po[y]=tot;
    bb[tot].st=y;bb[tot].en=x;
}
inline void get_root(int x,int last){
    int i;
    for(siz[x]=1,i=po[x];i;i=ne[i])
      if(bb[i].en!=last){        get_root(bb[i].en,x);
        siz[x]+=siz[bb[i].en];
        s[x]=max(s[x],siz[bb[i].en]);
      }
    s[x]=max(s[x],n-siz[x]);
    if(s[root]==s[x]) o[++o[0]]=x;
    else if(s[root]>s[x]) root=x,o[o[0]=1]=x;
}
inline void get_hash(int x,int last){
    int i;
    LL sum=0;
    for(siz[x]=1,i=po[x];i;i=ne[i])
      if(bb[i].en!=last&&can!=i&&(can^1)!=i){        get_hash(bb[i].en,x);
        sum+=hash[bb[i].en];
        siz[x]+=siz[bb[i].en];
      }
    hash[x]=(sum*(LL)p)^r[siz[x]];
}
inline void add_2(int x,int y,int va,int co){
    next[++tot]=point[x];point[x]=tot;
    aa[tot].st=x;aa[tot].en=y;aa[tot].va=va;aa[tot].co=co;
    next[++tot]=point[y];point[y]=tot;
    aa[tot].st=y;aa[tot].en=x;aa[tot].va=0;aa[tot].co=-co;
}
inline int SPFA(int x,int y){
    int h=0,t=1,u,i;
    memset(use,1,sizeof(use));
    memset(pre,0,sizeof(siz));
    memset(dis,127/3,sizeof(dis));
    l[t]=x;dis[x]=0;
    while(h!=t){        h=h%D+1;u=l[h];use[u]=true;
        for(i=point[u];i;i=next[i])
          if(aa[i].va>0&&dis[aa[i].en]>dis[u]+aa[i].co){            dis[aa[i].en]=dis[u]+aa[i].co;
            pre[aa[i].en]=i;
            if(use[aa[i].en]){                use[aa[i].en]=false;
                t=t%D+1;
                l[t]=aa[i].en;
            }
          }
    }
    return dis[y];
}
inline int ISAP(int x,int y){
    int minn=inf,i;
    for(i=y;i!=x;i=aa[pre[i]].st)
      minn=min(minn,aa[pre[i]].va);
    for(i=y;i!=x;i=aa[pre[i]].st){        aa[pre[i]].va-=minn;
        aa[pre[i]^1].va+=minn;
    }
    return minn;
}
inline void dp(int x,int last){
    int i,j,k;
    for(i=po[x];i;i=ne[i])
      if(bb[i].en!=last&&can!=i&&(can^1)!=i) dp(bb[i].en,x);
    for(i=1;i<=n;++i){        if(hash[i]==hash[x]){            memset(point,0,sizeof(point));
            for(tot=1,j=po[i];j;j=ne[j]) add_2(bb[j].en+n+1,T,1,0);
            for(j=po[x];j;j=ne[j])
              if(bb[j].en!=last&&can!=j&&(can^1)!=j){                add_2(1,bb[j].en+1,1,0);
                for(k=po[i];k;k=ne[k])
                  if(hash[bb[j].en]==hash[bb[k].en]) add_2(bb[j].en+1,bb[k].en+n+1,1,f[bb[j].en][bb[k].en]);
              }
            int minn=1,ans=0;
            while(minn!=inf){                minn=SPFA(1,T);
                if(minn!=inf) ans+=minn*ISAP(1,T);
            }
            f[x][i]=ans+(a[x]!=b[i]);
        }
    }
}
int main(){
    srand(233);
    int i,x,y;
    scanf("%d",&n);
    memset(use,1,sizeof(use));
    for(tot=1,i=1;i<n;++i){        scanf("%d%d",&x,&y);
        add_1(x,y);
    }
    for(i=1;i<=n;++i) scanf("%d",&a[i]);
    for(i=1;i<=n;++i) scanf("%d",&b[i]);
    s[0]=inf;get_root(1,0);
    if(o[0]==2){        for(i=po[o[1]];i;i=ne[i])
          if(bb[i].en==o[2]){            can=i;break;
          }
        root=++n;
        a[n]=b[n]=0;
        add_1(n,o[1]);
        add_1(n,o[2]);
    }
    for(i=1;i<=n;++i) r[i]=(LL)rand();
    get_hash(root,0);
    memset(f,127/3,sizeof(f));
    dp(root,0);
    int ans=inf;
    for(i=1;i<=n;++i)
      ans=min(ans,f[root][i]);
    printf("%d\n",ans);
}

[bzoj3197][SDOI2013]assassin相关推荐

  1. [BZOJ3197][Sdoi2013]assassin(树形DP+树同构+二分图最优匹配)

    关于树同构,有一个神奇的性质: 一棵树的重心只有 111 个或 2" role="presentation" style="position: relative ...

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

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

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

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

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

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

  5. luogu P3306 [SDOI2013] 随机数生成器(BSGS,数列求通项,毒瘤特判)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 发个水题的 题解证明我还在() luogu P3306 [SDOI2013] 随机数生成器 Webli ...

  6. bzoj3122 [SDOI2013]随机数生成器

    bzoj3122 [SDOI2013]随机数生成器 给定一个递推式, \(X_i=(aX_{i-1}+b)\mod P\) 求满足 \(X_k=t\) 的最小整数解,无解输出 \(-1\) \(0\l ...

  7. BZOJ3123: [Sdoi2013]森林

    BZOJ3123: [Sdoi2013]森林 Description 小Z有一片森林,含有N个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有M条边. 小Z希望执行T个操作,操作有两类: ...

  8. Light OJ 1406 Assassin`s Creed 减少国家DP+支撑点甚至通缩+最小路径覆盖

    标题来源:Light OJ 1406 Assassin`s Creed 意甲冠军:向图 派出最少的人经过全部的城市 而且每一个人不能走别人走过的地方 思路:最少的的人能够走全然图 明显是最小路径覆盖问 ...

  9. P3302 SDOI2013森林

    P3302 [SDOI2013]森林 题意: 一片森林,有n个节点,m个边,现在有t个操作, Q x y k:Q x y k 查询点 x 到点 y 路径上所有的权值中,第 ·k 小的权值是多少 L x ...

  10. P3301 [SDOI2013]方程

    P3301 [SDOI2013]方程 题意: 题解: 插板法介绍 首先要先讲组合数学的一个方法:插板法 问题引出:把10个球放进三个盒子,每个箱子至少一个有多少种分法? 10个球就有9个空隙,我们可以 ...

最新文章

  1. Windbg 教程-调试非托管程序的基本命令下
  2. RANK() OVER(PARTITION BY deptno ORDER BY empno)
  3. android 投影仪,不要购买投影仪, 安卓手机投屏很简单, 每个手机都可以
  4. 关于CSS属性display:none和visible:hidden的区别
  5. TensorFlow、MXNet、Keras如何取舍? 常用深度学习框架对比
  6. 语言用加法实现加饭运算_「编程之美」用C语言实现状态机(超实用)
  7. nvidia docker容器不支持中文的解决办法_用docker搭建深度学习实验环境
  8. 2021暑假每日一题 【week2 完结】
  9. CF868F Yet Another Minimization Problem
  10. vector中删除元素后,如何有效的释放无效元素的内存
  11. jdbctemplate 开启事务_浅入浅出 Spring 事务传播实现原理
  12. 小米回应设备被谷歌禁用;苹果中国宣布 2019 款 iPad 降价;Wine 5.0-rc4 发布 | 极客头条...
  13. 计算机组成 结构 华南理工,计算机组成原理-2019春华工网络教育随堂练习
  14. 【锁】redis加锁的几种方法
  15. bs结构管理系统 服务器多少钱,购买BS或CS架构的进销存软件哪个更划算
  16. 平面坐标转大地坐标(经纬度)
  17. 数独解法-变形数独(第三讲:数独进阶方法(摒除))
  18. springboot--入门程序实现CRUD操作
  19. 涛思数据创始人陶建辉荣获“2020中国开源杰出贡献人物”奖
  20. 给IOS初学者及新手的建议

热门文章

  1. html collapse不重叠,html – border-collapse的组合:collapse和transform:translate
  2. cogs——2098. Asm.Def的病毒
  3. [COGS2287][HZOI 2015]疯狂的机器人(NTT)
  4. 根据当前谷歌浏览器版本获取或更新更新chromedriver.exe
  5. unity操作详细教程
  6. httpclient-4.3.6工具类,方便直接使用
  7. sass 运算符的使用 和常见的基本函数
  8. Ubuntu下邮件服务器的配置——SendMail
  9. UnityShader源码2017---学习笔记与自我拓展001
  10. com.sun.mirror的jar包