• [HNOI2014]米特运输


    题目

    原题链接

    解说

    题目麻烦的一批。下面直接给简化版:
    给一棵树,每个点有一个权值,要求修改一些点的权值,使得:
    ①同一个父亲的儿子权值必须相同
    ②父亲的取值必须是所有儿子权值之和
    问最小要修改几个点。
    很显然这是一个树形DP。
    由于这个要求,树上只要有一个点确定,全树的权值就都确定了。那么我们只要计算将路径上权值的累乘积和计算到这里度的累乘积即为(f[i])(f[i])相同的表示他们同属于同一种合法方案,最后(sort)一遍寻找相同最多的即可。最后输出(n-maxn)
    注意将所有权值累乘会爆(long long),但使用高精度太麻烦,巧妙运用(log)转为加法。(小技巧)

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const double minn=1e-6;
    const int maxn=500000+3;
    struct node {
        int to,next;
    }a[maxn*2];
    double val[maxn];
    int v[maxn],head[maxn],s[maxn],cnt;
    void add(int x,int y){
        a[++cnt].next=head[x];
    	a[cnt].to=y;
    	head[x]=cnt;
    }
    void dfs(int x,int fa,double ans){
        val[x]=ans+log(v[x]),s[x]--;
        for(int i=head[x];i;i=a[i].next){
        	int v=a[i].to;
        	if(v==fa) continue;
        	dfs(v,x,ans+log(s[x]));
        }
    }
    int main(){
    	ios::sync_with_stdio(false);
        int n,x,y,maxx=0,js=1;
        cin>>n;
        for(int i=1;i<=n;i++) cin>>v[i];
        for(int i=1;i<n;i++){
        	cin>>x>>y;
    		add(x,y);
    		add(y,x);
    		s[x]++;
    		s[y]++;
    	}
        s[1]++;
    	dfs(1,0,0);
        sort(val+1,val+1+n);
        for(int i=2;i<=n;i++){
        	if(val[i]-val[i-1]<minn) js++;//注意double的比较方式
        	else maxx=max(maxx,js),js=1;
        }
        cout<<n-maxx;
    }
    

    幸甚至哉,歌以咏志。

  • 相关阅读:
    计算闰年
    三个数比较大小
    剪刀石头布编辑
    二进制转换,八进制,十六进制转换
    原来我学的还是不够。。。
    认知是一切的基础
    spark学习笔记-java调用spark简单demo
    spark学习笔记-RDD
    Sublime Text3时间戳查看转换插件开发
    Spring Boot + Freemarker多语言国际化的实现
  • 原文地址:https://www.cnblogs.com/DarthVictor/p/12781252.html
Copyright © 2020-2023  润新知