1. 程式人生 > >[HEOI2015]兔子與櫻花 樹規+貪心

[HEOI2015]兔子與櫻花 樹規+貪心

鬼能想到是個貪心。明明覺得是樹規啊。。又完美爆零。。
       從葉子節點往上更新,能保證最優解(這塊想了半天)。        證明:當你的子樹上有能刪的點而你不刪時,可能會對子樹的根節點有利,最好的情況是使子樹根節點由不可刪除變為可刪除。但是,既然最終可能刪一個點,還不如直接刪現成能刪的呢。。        用wei[]記錄每個節點的權值(花數+兒子數),在更新結果時將權值更新即可。
#include
#include
#include
#include
#include
#include
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 2000500
int n,m;
vector son[N];
int wei[N];
int ji[N];
int ans;
bool tmp(const int &a,const int &b)
{
     return wei[a]
}
void dp(int x)
{
     if(ji[x]==0)
       return;
     pos(i,0,ji[x]-1)
     {
         dp(son[x][i]);
     }
     sort(son[x].begin(),son[x].end(),tmp);
     pos(i,0,ji[x]-1)
     {
       if(wei[x]-1+wei[son[x][i]]<=m)
       {
          ans++;
          wei[x]+=wei[son[x][i]]-1;
       }
     }
     
}
int main()
{
    freopen("sakura.in","r",stdin);
    freopen("sakura.out","w",stdout); 
    cin>>n>>m;
    pos(i,1,n)
      scanf("%d",&wei[i]);
    pos(i,1,n)
    {
      scanf("%d",&ji[i]);
      wei[i]+=ji[i];
      pos(j,1,ji[i])
      {
          int p;
          scanf("%d",&p);
          p++;
          son[i].push_back(p);
      }
    }
    dp(1);
    cout<<ans;
    //while(1);
    return 0;
}