Codeforces-964D Destruction of a Tree(贪心)

题意:给你一颗节点数目为n的树,问你能否每次删除一个度为偶数的节点,同时与该节点相连的路也被删除,能否在多次删除操作后删除掉整棵树

题解:从根开始dfs处理出每个节点到根的距离。然后贪心的删除离根最远的偶数度节点。如何证明这个结论是正确的呢?(补题目的时候是多画图然后猜的结论,因为WA了两发后以为是错误的,然后请教了别人,并且证明了这个结论的正确性)因为离根最远的偶数度节点(其子孙一定都是奇数度数的),在将其删除后它所在的那颗树一定被分成两个奇数节点数(注意是节点数!因为只有奇数树才能进行删除操作)的树,从而它的子孙也可以开始删除操作,所以从该点开始删除一定是最优解,如果在当前情况下仍然无法删除所有点,则输出NO。

写的很撮的代码,去看别人的代码,发现他们写的都比我好

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <vector>
#include <cstring>
#include <iomanip>
#include <set>
#include<ctime>
//CLOCKS_PER_SEC
#define se second
#define fi first
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define Pii pair<int,int>
#define Pli pair<ll,int>
#define ull unsigned long long
#define pb push_back
#define fio ios::sync_with_stdio(false);cin.tie(0)
const int N=4e5+5;
const ull base=163;
const int INF=0x3f3f3f3f;
using namespace std;
int head[N],nx[N],to[N];
int tot=1;
struct node {
    int le,du,num;
    friend bool operator < (node a, node b){
        if(a.le==b.le)
        {
            return a.du>b.du;
        }
        return a.le>b.le;
    }
}L[N];
void add(int u,int v){
    to[tot]=v;
    nx[tot]=head[u];
    head[u]=tot++;
}
int dfs(int x,int pre){
    for(int i=head[x];i;i=nx[i]){
        int v=to[i];
        if(v==pre)continue;
        if(v!=pre)L[x].le+=dfs(v,x);
    }
    return L[x].le;
}
bool vis[N];
vector<int>ans;
int main(){
    fio;
    int n;
    cin>>n;
    int S=-1;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        if(x==0){
            S=i;
            continue;
        }
        add(i,x);
        add(x,i);
        L[i].du++,L[x].du++;
        L[i].le=1;
        L[i].num=i;
    }
    if(n%2==0)return cout<<"NO\n",0;
    L[S].le=1;
    L[S].num=S;
    dfs(S,S);
    priority_queue<node>q;
    for(int i=1;i<=n;i++){
        if(L[i].du%2==0)
            q.push(L[i]);
    }
    while(!q.empty()){
        node x=q.top();
        q.pop();
        if(vis[x.num]||L[x.num].du%2==1)continue;
        vis[x.num]=1;
        ans.pb(x.num);
        for(int i=head[x.num];i;i=nx[i]){
            int v=to[i];
            if(L[v].du)L[v].du--;
            if(L[v].du==0&&vis[v]==0){
                vis[v]=1;
                ans.pb(v);
            }
            else if(L[v].du%2==0&&!vis[v]){
                q.push(L[v]);
            }
        }
    }
    if(ans.size()==n){
        cout<<"YES"<<endl;
        for(auto i:ans){
            cout<<i<<endl;
        }
    }
    else cout<<"NO"<<endl;
    return 0;
}

 

posted @ 2018-04-18 22:36  采蘑菇的小西佬  阅读(171)  评论(0编辑  收藏  举报