樹形dp一道,開始想到的狀態table[i][j]表示節點i為根的子樹花費上限為j所能供給的最多觀眾,後來發現花費並沒有辦法得出,所以換另一種狀態表示table[i][j]表示以節點i為根的子樹供給j位觀眾所能得到的最大利益,
狀態轉移方程為 table[i][j] = max(∑table[a][b])(a為i的兒子節點,∑b = j),複雜度為O(n*m^2),貌似要逾時,不過資料還是沒那麼恐怖的,沒有想到怎麼最佳化到O(n*m)。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>#include <map>#include <string>#include <climits> #include <set>#include <string> #include <sstream>#include <utility>#include <ctime>//#pragma comment(linker, "/STACK:1024000000,1024000000") using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::getline;using std::make_pair;using std::greater;const int MAXN(3010);const int INFI((INT_MAX-1) >> 1);struct EDGE{int v, w;EDGE *next;};EDGE *first[MAXN];EDGE pool[MAXN];EDGE *rear;void init(){memset(first, 0, sizeof(first));rear = pool;}void insert(int tu, int tv, int tw){rear->v = tv;rear->w = tw;rear->next = first[tu];first[tu] = rear++;}int table[MAXN][MAXN];int value[MAXN];int num[MAXN];int N, M, tm;void dfs(int cur, int limit, int tw){if(cur >= tm){table[cur][0] = -tw;table[cur][1] = value[cur]-tw;num[cur] = 1;return;}table[cur][0] = -tw;int temp = 0;for(EDGE *i = first[cur]; i; i = i->next){dfs(i->v, limit, i->w);temp += num[i->v];for(int j = temp; j >= 0; --j)for(int k = 0; k <= j; ++k)table[cur][j] = max(table[cur][j], table[cur][j-k]+table[i->v][k]);}num[cur] = temp;}int main(){while(~scanf("%d%d", &N, &M)){init();tm = N-M+1;int tv, tw;for(int i = 1; i < tm; ++i){int tl;scanf("%d", &tl);for(int j = 0; j < tl; ++j){scanf("%d%d", &tv, &tw);insert(i, tv, tw);}}for(int i = tm; i <= N; ++i){scanf("%d", value+i);}for(int i = 1; i <= N; ++i){for(int j = 0; j <= M; ++j)table[i][j] = -INFI;num[i] = 0;}dfs(1, M, 0);int ans = M;while(table[1][ans] < 0)--ans;printf("%d\n", ans);}return 0;}