zoukankan      html  css  js  c++  java
  • FZOJ 4108 世界树的考验

    这题的转换非常的巧妙。

    众所周知,树上一条路径点权异或有非常好的性质,可惜这道题是边权啊,这就需要一个转化:

    • 设每个点的点权为与它相连的所有边的边权的异或和。那么使得每个点的点权为(0)就是题目要求达到的状态。
      证明:考虑度数为(1)的点,显然与他们相连的边为(0),然后把他们删掉,又会有很多度数为(1)的点(类似于拓扑排序)……最后可以推出所有边都变成(0)

    那么,每次操作把一条路径的每一条边异或同一个数(x),相当于把路径两端的点权都异或(x),其他点权都不变(大家可以自己考虑考虑)。

    现在问题变成了,给你若干个数(数值 (leq) 15),每次给两个数异或上同一个数,问至少多少次可以把所有数变成(0)

    显然相同的数直接异或掉就可以了,所以可以看成若干个不同的数。设(f[S])表示当状态为(S)时需要的最少操作数((i)属于集合(S)当且仅当 ((1<<i&S)!=0) ),其实就是一个状态压缩,然后发现状态总数非常少(只有(2^{16})种),所以可以直接一发记忆化搜索解决。

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    const int N=100009,INF=1<<30;
    int siz[N],point[N],n,S,f[N*10];
    
    void init()
    {
    	scanf("%d",&n);
    	int x,y,z;
    	for (int i=1;i<n;i++)
    	{
    		scanf("%d %d %d",&x,&y,&z);
    		point[x]^=z,point[y]^=z;
    	}
    	for (int i=0;i<=n;i++)
    		siz[point[i]]++;
    }
    
    int dfs(int S)
    {
    	if(S==0)
    		f[S]=0;
    	if(f[S]!=INF)
    		return f[S];
    	for (int i=0;i<=15;i++)
    		if(S&1<<i)
    			for (int j=0;j<=15;j++)
    				if(i!=j&&(S&1<<j))
    				{
    					int p=S^(1<<i)^(1<<j)^(1<<(i^j));
    					if(S&(1<<(i^j)))
    						f[S]=min(f[S],dfs(p)+2);
    					else
    						f[S]=min(f[S],dfs(p)+1);
    				}
    	return f[S];
    }
    
    void work()
    {
    	int ans=0;
    	for (int i=1;i<=15;i++)
    		ans+=siz[i]/2,siz[i]&1?(S^=(1<<i)):0;
    	for (int i=0;i<1<<16;i++)
    		f[i]=INF;
    	printf("%d
    ",ans+dfs(S));
    }
    
    int main()
    {
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    DateTime的精度小问题
    使用For XML PATH 会影响Cross Apply 返回
    一个update的小故事
    行大小计算测试
    Sql Server 2008R2 遇到了BCP导入各种中文乱码的问题
    php-fpm 启动不了 libiconv.so.2找不到
    Git使用教程
    支付宝接口使用文档说明 支付宝异步通知
    Linux(CentOs6.4)安装Git
    NGINX防御CC攻击教程
  • 原文地址:https://www.cnblogs.com/With-penguin/p/12705843.html
Copyright © 2011-2022 走看看