美团2024届秋招笔试第一场编程 【小美的树上染色】

题目描述:

小美拿到了一棵树,每个节点有一个权值。初始每个节点都是白色。

小美有若干次操作,每次操作可以选择两个相邻的节点,如果它们都是白色且权值的乘积是完全平方数,小美就可以把这两个节点同时染红。

小美想知道,自己最多可以染红多少个节点?

开始看到这个题的时候,已经下意识认定这是一道树形DP,状态定义大概是f[i][0],f[i][1],分别表示

i节点是白色情况下,i子树内包含的红节点最大数;i节点是红色情况下,i子树内包含的红节点最大数。f[i][0]的求法还是比较好求的:假设i的儿子是j,则f[i][0]+=max(f[j][0],f[j][1])。但求f[i][1]的时候好像卡住的,有点想法,不知道对不对。 

然后我把题给旁边一佬看了,结果令我没想到的是,他看到这个题,首先就是一种贪心(在输入的时候处理答案,对输入的俩个节点,如果它们权值相乘能凑成平方数就标记,也就是不建树)然后给我过了样例。当时听完之后,想了想【啊哈,这种题不建树是能写出来的吗,不过想了一些样例,好像确实是这样】。再想了几分钟之后,感觉不对啊,于是搞了个样例,它的解法是依赖输入的顺序的。【虽然他的解法有缺陷,但我发现我这固定思维是个很大缺点哪,一眼DP(虽然dp和贪心还是有很大关联),根本没往其它方向想】 这让我有了个认识【哪怕你AC了一道题,也要有看题解或者别人代码的必要,可以发散思维

之后结合他的想法,发现这个题确实可以不用dp,建树完之后从叶子节点一直往上贪心。

#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

typedef long long LL;
const int N=1e5+10;
vector<int>g[N];
int n;
int st[N];
int ans;
LL w[N];


bool fun(LL x)
{
    LL d=sqrt(x);
    return d*d==x;
}
    
void dfs(int u,int fa)
{
    for(auto x:g[u]){
	   if(x==fa)continue;//保证不往回走,确保时间复杂度O(N)
	   dfs(x,u);
	   if(fun(w[u]*w[x])&&(!st[x]&&!st[u])){
	       ans+=2;
	       st[x]=1;
	       st[u]=1;
	   }
    }
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)cin>>w[i];
    for(int i=0;i<n-1;i++){
	   int u,v;
	   cin>>u>>v;
	   g[u].push_back(v);
	   g[v].push_back(u);
    }
    dfs(1,-1);
    cout<<ans<<endl;
    return 0;
}

【很充实的一天,下午到晚上,听了一节3.5h的Linux和3h的C++,Linux敲了很多指令,

C++学到了缺省参数,函数重载,一点汇编,C++的函数名修饰规则(C为什么不支持函数重载的原因),引用...

加油!制定9_18到12_18的任务必须完成!

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值