leetcode2603收集树中金币
这道题如果能够想到从叶子进行考虑的话就会简单一些
首先如果一个叶子的贡献是0的话,那么这个点对整个问题没有任何影响,直接删去即可,删去之后可能会产生新的可以删去的节点,所以我们用类似拓扑排序的方法来删除这些点
那么剩下的叶节点都是贡献为1的点,我们让这些点走一步,删除到达的点,
那么每一个贡献为1的叶子都可以被 剩下的没有被删除的节点来获取
在最后没有被删除的点中任选一个点作为起点都是可以的,因为每条边都是会经过两次的,否则就与上面的矛盾。
答案就是没有被删掉的边的数量*2
class Solution {
public:
int collectTheCoins(vector<int>& coins, vector<vector<int>>& edges) {
int n=coins.size();
int x,y;
vector<int> v[n+5];
int d[n+5];
bool del[n+5],bz[n+5];
queue<int> q;
for (int i=0;i<n;i++) d[i]=0;
for (int i=0;i<n;i++) del[i]=0;
for (int i=0;i<n;i++) {
if (coins[i]) cout<<i<<endl;
}
cout<<endl;
for (auto i:edges) {
x=i[0];
y=i[1];
v[x].emplace_back(y);
v[y].emplace_back(x);
d[x]++;
d[y]++;
}
for (int i=0;i<n;i++) {
if (d[i]==1 && !coins[i]) {
q.push(i);
del[i]=1;
}
}
while (!q.empty()){
x=q.front(); q.pop();
for (auto i:v[x]){
if (del[i]) continue;
d[i]--;
if (d[i]==1 && !coins[i]) {
del[i]=1;
q.push(i);
}
}
}
for (int i=0;i<n;i++) {
if (del[i]) cout<<i<<endl;
}
for (int i=0;i<n;i++) {
if (!del[i] && d[i]==1) {
q.push(i);
del[i]=1;
}
}
while (!q.empty()){
x=q.front(); q.pop();
for (auto i:v[x]){
if (del[i]) continue;
d[i]--;
if (d[i]==1) del[i]=1;
}
}
int ans=0;
for (int i=0;i<n;i++) {
if (del[i]) continue;
for (auto j:v[i]){
if (!del[j]) ans++;
}
}
ans=ans;
return ans;
}
};

浙公网安备 33010602011771号