1. 程式人生 > >bzoj4027: [HEOI2015]兔子與櫻花 貪心

bzoj4027: [HEOI2015]兔子與櫻花 貪心

行為 我們 urn end algorithm space def .... bsp

本人總覺得貪心不清真不是正解,可有的騷題他就是正解而且我還老碰上,所以說,有的時候是要感性理解一下或者證一下,貪心大佬.....

這個題看數據,dp太難,往貪心那邊想一下吧.....

本題的做法是建樹,從葉結點開始合並代價直到不行為止(證明:首先假設我們已經找到一個最優解但他不是從葉到根合並到死,那麽對於合並的點我們可以把其中的點從低到高依次再合並他的子節點,第一層由於合並了子節點而他又是最優解所以最多合並一個子節點並把它自己釋放,第二層同理....最高層因為是最優解肯定不能再合並子節點;隊友不適合冰點的點肯定不能再合並,所以我們葉到根每個點都是合並到不能合並,證畢),在合並之後只要把他的代價加上就好,因為他的兒子不可能再合並到他的父親所以他的父親只能合並它和他的兄弟,所以每個節點只可能去合並直系兒子。

證明好累.......

這個兒子當然要從代價小到代價大合並,所以鄰接表和鄰接矩陣都是不好實現的,因為要動態,所以vector最方便....

考試的時候總覺得貪心不清真,就隨便大了幾個貪心,就掛零了....

#include<cstdio>
#include<vector>
#include<algorithm>
#define MAXN 2000005
using namespace std;
vector<int>e[MAXN];
int c[MAXN],n,son[MAXN],ans,m;
int comp(const int a,const
int b) { return c[a]<c[b]; } void dfs(int x) { for(int i=0;i<e[x].size();i++) dfs(e[x][i]); sort(e[x].begin(),e[x].end(),comp); c[x]+=e[x].size(); for(int i=0;i<e[x].size();i++) { if(c[x]+c[e[x][i]]-1>m)break; ans++; c[x]+=c[e[x][i]]-1; } }
int main() { //freopen("sakura.in","r",stdin); //freopen("sakura.out","w",stdout); scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%d",&c[i]); for(int i=0;i<n;i++) { scanf("%d",&son[i]); for(int j=1;j<=son[i];j++) { int x; scanf("%d",&x); e[i].push_back(x); } } dfs(0); printf("%d",ans); return 0; }

bzoj4027: [HEOI2015]兔子與櫻花 貪心