zoukankan      html  css  js  c++  java
  • [SDOI2013]刺客信条

    Description

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

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

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

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

    Solution

    首先固定一棵树,枚举另一棵树,显然另一棵树只有与固定的树同构才有可能产生贡献
    如果固定的树以重心为根,那么另一棵树最多就只有重心为根才有可能同构了(可能有两个)
    然后就是求改动次数最小值,设 (f[x][y]) 表示以第一棵树 (x) 为根的子树内和 第二棵树内 (y) 为根的子树内,达到目标最少需要改动的次数
    我们发现只有同构的子树需要决策,我们把同构的子树分别拿出来,我们要做的就是做一个匹配,跑一边 (KM) 或者费用流就好了
    (f[x][y]) 要记忆化一下,判断同构用树哈希即可

    #include<bits/stdc++.h>
    #define pb push_back
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    typedef unsigned long long ll;
    const int N=1410,bas=10007;
    int n,head[N],nxt[N*2],to[N*2],num=0,sz[N],F[N]={N},rt=0,a[N],b[N];ll v[N];
    vector<int>v1[N],v2[N];
    inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
    inline void getroot(int x,int last){
    	sz[x]=1;F[x]=0;
    	for(int i=head[x],u;i;i=nxt[i]){
    		if((u=to[i])==last)continue;
    		getroot(u,x);sz[x]+=sz[u];
    		F[x]=max(F[x],sz[u]);
    	}
    	F[x]=max(F[x],n-sz[x]);
    	if(F[x]<F[rt])rt=x;
    }
    inline bool comp(const int &i,const int &j){return v[i]<v[j];}
    inline void dfs(int x,int last,vector<int>*V){
    	sz[x]=1;v[x]=0;vector<int>().swap(V[x]);
    	for(int i=head[x],u;i;i=nxt[i]){
    		if((u=to[i])==last)continue;
    		dfs(u,x,V);sz[x]+=sz[u];
    		V[x].pb(u);
    	}
    	sort(V[x].begin(),V[x].end(),comp);
    	for(int i=V[x].size()-1;i>=0;i--)v[x]=v[x]*N+v[V[x][i]];
    	v[x]=v[x]*N+sz[x];
    }
    int f[N][N],c[N][N];
    namespace sks{
    	int head[N],nxt[N*8],to[N*8],num=1,c[N*8],dis[N*8],S,T,ans=0;
    	queue<int>Q;int f[N],pre[N];bool vis[N];
    	inline void link(int x,int y,int z,int co){
    		nxt[++num]=head[x];to[num]=y;head[x]=num;dis[num]=z;c[num]=co;
    		nxt[++num]=head[y];to[num]=x;head[y]=num;dis[num]=0;c[num]=-co;
    	}
    	inline void init(){for(int i=S;i<=T;i++)head[i]=0;num=1;ans=0;}
    	inline bool spfa(){
    		for(int i=S;i<=T;i++)f[i]=N,vis[i]=0;
    		Q.push(S);vis[S]=1;f[S]=0;
    		while(!Q.empty()){
    			int x=Q.front();Q.pop();
    			for(int i=head[x],u;i;i=nxt[i]){
    				if(dis[i]<=0)continue;
    				u=to[i];
    				if(f[x]+c[i]<f[u]){
    					f[u]=f[x]+c[i];pre[u]=i;
    					if(!vis[u])Q.push(u),vis[u]=1;
    				}
    			}
    			vis[x]=0;
    		}
    		if(f[T]==N)return false;
    		int x=T;ans+=f[T];
    		while(x)dis[pre[x]]--,dis[pre[x]^1]++,x=to[pre[x]^1];
    		return true;
    	}
    }
    inline int solve(int n){
    	sks::init();
    	sks::S=0;sks::T=n+n+1;
    	for(int i=1;i<=n;i++){
    		sks::link(sks::S,i,1,0);sks::link(i+n,sks::T,1,0);
    		for(int j=1;j<=n;j++)sks::link(i,j+n,1,c[i][j]);
    	}
    	while(sks::spfa());
    	return sks::ans;
    }
    inline int sec(int x,int y){
    	if(f[x][y]!=-1)return f[x][y];
    	f[x][y]=b[y]^a[x];
    	for(int i=0,li=v1[x].size()-1;i<=li;i++){
    		int j=i;
    		while(j<li && v[v1[x][j+1]]==v[v1[x][i]])j++;
    		for(int k=i;k<=j;k++)
    			for(int l=i;l<=j;l++)sec(v1[x][k],v2[y][l]);
    		for(int k=i;k<=j;k++)
    			for(int l=i;l<=j;l++)c[k-i+1][l-i+1]=sec(v1[x][k],v2[y][l]);
    		f[x][y]+=solve(j-i+1);
    		i=j;
    	}
    	return f[x][y];
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      cin>>n;
      int x,y,ans=N;
      for(int i=2;i<=n;i++){
    	  gi(x);gi(y);
    	  link(x,y);link(y,x);
      }
      for(int i=1;i<=n;i++)gi(a[i]);
      for(int i=1;i<=n;i++)gi(b[i]);
      getroot(1,1);dfs(rt,rt,v2);ll tmp=v[rt];
      for(int i=1;i<=n;i++){
    	  dfs(i,i,v1);
    	  if(v[i]==tmp){
    		  memset(f,-1,sizeof(f));
    		  ans=min(ans,sec(i,rt));
    	  }
      }
      cout<<ans<<endl;
      return 0;
    }
    
    
  • 相关阅读:
    Session、Cookie、Application、ViewState和Cache 这四者的区别
    用C#构造HighChart类库,把数据转换成JSON第二阶段完成50%API,已经能满足项目要求了
    HttpHandler 在SharePoint 2010中的应用
    SharePoint 2010 在多台前端环境 还原 网站集 问题解析
    SharePoint 2010 PowerShell 系列 之 文档管理 高级应用和企业案例(文档迁移)
    设计模式策略模式
    CentOS7 安装Hbase集群
    CentOS7 安装zookeeper
    CentOS7 安装Hadoop集群环境
    Django Rest Framework关闭CSRF验证
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9085169.html
Copyright © 2011-2022 走看看