题目:小美拿到了一棵树,每个节点有一个权值。初始每个节点都是白色。
小美有若干次操作,每次操作可以选择两个相邻的节点,如果它们都是白色且权值的乘积是完全平方数,小美就可以把这两个节点同时染红。小美想知道,自己最多可以染红多少个节点?
思路:由于只在乎相邻节点权值乘积为完全平方数的,所以不必使用所有的边建立树,而是使用乘积为平方数的边构造一棵树,然后对这棵树进行深度优先搜索,画图可知从树的叶子开始涂色,才是可以涂最多的方法。
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)
}()