• JZOJ3296. 【SDOI2013】刺客信条


    Description

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

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

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

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

    Input



    第一行给出一个整数n,表示密室的个数。

    第二行至第n 行,每行给出两个整数a 和b,表示第a 个密室和第b 个密室之间存在一条通道。

    第n+1 行,给出n 个整数,分别表示当时每个密室的启动情况(0 表示关闭,1 表示启动)。

    第n+2 行,给出n 个整数,分别表示密码中每个密室的启动情况。

    Output

    输出只有一行,即输出最少改动标记次数。
     

    Sample Input

    4
    1 2
    2 3
    3 4
    0 0 1 1
    1 0 0 0

    Sample Output

    1
     

    Data Constraint

    对于30%的数据,n<=10。

    对于60%的数据,n<=100。

    对于100%的数据,n<=700,且每个密室至多与11 个密室相通。
     

    Hint

    样例解释:

    密室的编号是可以变的!将第三个密室关闭后,在当前标记和密码之间,存在1->4,2->3,3->2,4->1 的对应关系,重新编号后连接情况没有改变,且标记与密码对应。对于更一般的情况,存在一个1 到n 的置换P,使得对于任意密室之间的道路u-v,都一定有密码密室中的道路P(u)-P(v);如果不存在密室之间的道路u-v,则一定没有密码密室中的道路P(u)-P(v)。

    (题目背景吐槽:圣殿骑士团,在14世纪初被灭,根本不可能出现在1486年。)

    灵感来自:https://blog.csdn.net/weixin_30932215/article/details/98347121

    正解:

    题目大意即:可以将一颗树随便转,要和原来的树同构,然后将两棵树对应的点异或之和取min。

    确定原来树的重心为根,这样新的树的根就确定了。若重心有两个,则删掉两点连边,新开一个根节点(重心)连接两重心。(这样处理比较方便)

    关于树哈希(详见oi-wiki),先存下来原先的树,后面依次搞新的树,要开long long。

    枚举新的树的根,每次都做dp。f[x][y]表示 新的树以x为根的子树 与 原树以y为根的子树 相对应的异或之和。

    对于每对x,y(意义同上),如何选择各自儿子的匹配?由于儿子<=11,可以用状压DP(或费用流)。g[a][b]表示匹配完了x的儿子的前i个,b表示y的儿子的匹配状态,最后用g[都匹配完]更新当前f[x][y]。

    记得统计答案。

    code如下,码量较大,逾200行,3000byte。

    #include<bits/stdc++.h>
    #define inf 1000000007
    #define base 2333
    #define mod (long long)((1e9)+7)
    #define mid (l+r)/2
    using namespace std;
    int n,m,h[100005],cnt,a[1005],goal[1005],ans,fa[1005],g[15][(1<<11)+5];
    int rt1,rt2,rt,size[1005],w[1005],f[1005][1005],N,fu[1005];
    long long hosh[1005],hash[1005],tmp;
    struct node{
        int next,to,bz;
    }e[100005];
    int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=(x<<1)+(x<<3)+ch-48;
            ch=getchar();
        }
        return x*f;
    }
    void add(int x,int y)
    {
        //printf("Ok\n");
        e[++cnt].to=y;
        e[cnt].bz=1;
        e[cnt].next=h[x];
        h[x]=cnt;
    }
    void certroid(int x,int fa)
    {
        size[x]=1;
        w[x]=0;
        for(int i=h[x];i;i=e[i].next)
        {
            //printf("OK\n");
            int y=e[i].to;
            if(y!=fa)
            {
                certroid(y,x);
                size[x]+=size[y];
                w[x]=max(w[x],size[y]);
            }
        }
        w[x]=max(w[x],n-size[x]);
        //printf("node[%d]s=%d w=%d\n",x,size[x],w[x]);
        if(w[x]<=n/2)
        {
            if(!rt1)rt1=x;
            else rt2=x;
        }
    }
    void hdfs(int x)
    {
        //printf("Ok %d %d\n",x,fa[x]);
        int tot=0;
        long long ans,a[15];
        size[x]=1;hash[x]=0;
        for(int i=h[x];i;i=e[i].next)
        {
            int y=e[i].to;
            if(y!=fa[x]&&e[i].bz)
            {
                fa[y]=x;
                hdfs(y);
                size[x]+=size[y];
                a[++tot]=hash[y];
            }
        }
        sort(a+1,a+tot+1);ans=0;
        //if(x==4)printf("find %lld\n",ans);
        for(int i=1;i<=tot;i++)
        {
            ans=ans*base+a[i];
        }
        ans=ans*base+size[x]+1;
        hash[x]=ans;
    }
    void dp(int x,int u)
    {
        //printf("ber %d-%d %d-%d\n",x,fa[x],u,fa[u]);
        f[x][u]=(a[x]^goal[u]);
        int sona[15],sonb[15],la=0,lb=0;
        for(int i=h[x];i;i=e[i].next)
        {
            int y=e[i].to;
            if(y!=fa[x]&&e[i].bz)
            {
                sona[++la]=y;
            }
        }
        if(!la)
        {
            return;
        }
        for(int i=h[u];i;i=e[i].next)
        {
            int y=e[i].to;
            if(y!=fu[u]&&e[i].bz)
            {
                sonb[++lb]=y;
            }
        }
        for(int i=1;i<=la;i++)
        {
            for(int j=1;j<=lb;j++)
            {
                if(hash[sona[i]]==hash[sonb[j]])
                {
                    dp(sona[i],sonb[j]);
            //    if(x==1&&u==1)printf("f[%d][%d]=%d\n",sona[i],sonb[j],f[sona[i]][sonb[j]]);
                }
            }
        }
        memset(g,0x3f,sizeof(g));
        int ber=g[0][0];g[0][0]=0;
        for(int i=0;i<la;i++)
        {
            for(int s=0,ss;s<(1<<lb);s++)
            {
                if(g[i][s]>=ber)continue;
                for(int j=1;j<=lb;j++)
                {
                //if(x==2&&u==3&&i==0&&j==1&&!s)printf("BER\n");
                    if(((1<<(j-1))&s)==0)
                    {
                        if(hash[sona[i+1]]==hosh[sonb[j]])
                        {
                            ss=s+(1<<(j-1));;
                            g[i+1][ss]=min(g[i+1][ss],g[i][s]+f[sona[i+1]][sonb[j]]);
                        }
                    }
                }
            }
        }
        f[x][u]+=g[la][(1<<lb)-1];
        //if(x==2&&u==3)printf("F %d %d\n",f[2][3],f[1][4]);
    }
    int main ()
    {
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        n=read();cnt=1;
        for(int i=1,x,y;i<n;i++) 
        {
            x=read(),y=read();
            add(x,y);add(y,x);
        }
        for(int i=1;i<=n;i++)
        {
            a[i]=read();
        }
        for(int i=1;i<=n;i++)
        {
            goal[i]=read();
        }
        certroid(1,1);
        //printf("rt=%d %d\n",rt1,rt2);
        if(rt2)
        {
            for(int i=h[rt1];i;i=e[i].next)
            {
                int y=e[i].to;
                if(y==rt2)
                {
                    e[i].bz=e[i^1].bz=0;    
                }
            }
            add(n+1,rt1);add(rt1,n+1);
            add(n+1,rt2);add(rt2,n+1);
            rt=N=n+1;
        }else rt=rt1,N=n;
        
        
        fa[rt]=rt;
        hdfs(rt);
        for(int i=1;i<=N;i++)
        {
            hosh[i]=hash[i];
            //printf("ber=%lld\n",hosh[i]);
            fu[i]=fa[i];
        }
        tmp=hosh[rt],ans=inf;
        //printf("rt=%d\n",rt);
        for(int i=1;i<=N;i++)
        {
            fa[i]=i;
            //memset(size,0,sizeof(size)); 
            hdfs(i);
            long long ber=hash[i];
            //printf("Ok %lld-%lld\n",ber,tmp);
            if(ber==tmp)
            {
                //printf("OK %d\n",i);
                memset(f,0x3f,sizeof(f));
                dp(i,rt);
                ans=min(ans,f[i][rt]);
            }
        }
        printf("%d\n",ans);
        return 0;
    }
    Code
  • 相关阅读:
    配置ssl(阿里云+腾讯云)
    使用Nativefier将web页面打包为桌面应用
    临时切换淘宝源下载包
    ajax实现异步上传多图并且预览
    通过phpexcel插件导出报表功能实现
    ThinkPHP5.0自定义命令行的使用
    Longest Substring Without Repeating Characters
    计算机操作系统巡回置换算法
    HDU 2041 DP
    HDU 2044 DP (fibonacci)
  • 原文地址:https://www.cnblogs.com/HYDcn666/p/assassin_temples.html
Copyright © 2020-2023  润新知