Bootstrap

小美的树上染色题解

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

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

思路:由于只在乎相邻节点权值乘积为完全平方数的,所以不必使用所有的边建立树,而是使用乘积为平方数的边构造一棵树,然后对这棵树进行深度优先搜索,画图可知从树的叶子开始涂色,才是可以涂最多的方法。

const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void async function () {
    // Write your code here
    const nstr=await readline();
    const n=parseInt(nstr);
    const line=await readline();
    const weights=line.split(' ').map(val=>Number(val));
    function square(x)
    {
        return x*x
    }
    function isSquare(x)
    {
        const t = Math.sqrt(x);
        return square(Math.floor(t)) === x;
    }
    let connection=''
    const vertices=new Set()
    const adj=new Map()
    while(connection=await readline())
    {
        const arr=connection.split(' ').map(val=>Number(val));
        const n1=arr[0];
        const n2=arr[1];
        if(isSquare(weights[n1-1]*weights[n2-1]))
        {
            vertices.add(n1)
            vertices.add(n2);
            const n1neig=adj.get(n1)
            if(!n1neig)
                adj.set(n1,[n2])
            else
                n1neig.push(n2)
            const n2neig=adj.get(n2)
            if(!n2neig)
                adj.set(n2,[n1])
            else
                n2neig.push(n1)
        }
    }
   const visited=new Set()
   let sum=0
   const reds=new Set()
   const dfs=(v)=>
   {
        visited.add(v)
        const neigs=adj.get(v);
        for(const w of neigs)
        {
            if(!visited.has(w))
            {
                dfs(w);
                if(!reds.has(v)&&!reds.has(w))
                {
                    sum+=2;
                    reds.add(v);
                    reds.add(w)
                }
            }
        }
   }
   for(let vertice of vertices)
   {
    if(!visited.has(vertice))
        dfs(vertice)
   }
   console.log(sum)
}()

;