[BZOJ1722] [Usaco2006 Mar] Milk Team Select產奶比賽 解題報告
阿新 • • 發佈:2018-08-21
i++ http 理解 範圍 zoj 維數 class 一道 ()
首先,要明確這是一道動態規劃題(看著很像背包嘛)那我們要用什麽作為下表呢?
- 以牛奶量:牛奶量的數據範圍較大,最多只能開一維數組(除非你開滾動數組)。總體來說較難考慮。
- 以關系數:關系數最多只有 N - 1 對,可以給每頭牛開一個 MAXN 的數組,看起來更行得通。。。
還有,因為要考慮關系數的轉換問題,所以還有開一維[0/1]表示這頭牛取不取。
我們發現,這些關系是無環的,或者說這是一個森林(本來我想用拓撲排序,後來還是放棄了。。。),所以可以再建立一頭“牛祖先”,連接原來所有祖先,構成一棵樹(即無母親的節點都認0為母親)。
對於樣例,可以構成如圖的一棵樹:
整理一下,剛才講到建立一個 int f[MAXN][MAXN][2]; 的數組,f[i]j[j][op] 表示以第 i 個節點為根的樹 共有 j 對關系,op = 1 時表示取這個節點,op = 0 時表示不取。
可以把 關系數 作為背包容量,牛奶量 作為 價值
用分組背包的方法來考慮。
具體的部分自己慢慢理解吧。
上代碼——
#include<cstdio> #include<iostream> using namespace std; #define MAXN 505 #define INF 0x3f3f3f3f intN, X, ans; int c[MAXN], t; int head[MAXN], to[MAXN << 1], nxt[MAXN << 1], tot(0); int f[MAXN][MAXN][2]; void Add( int x, int y ){ to[++tot] = y; nxt[tot] = head[x]; head[x] = tot; } void DFS( int x, int fa ){ for ( int i = 1; i <= N; i++ ) f[x][i][0] = f[x][i][1] = -INF;//初始值均為負無窮for ( int i = head[x]; i; i = nxt[i] ){ if ( to[i] == fa ) continue; DFS( to[i], x );//先完成子節點 for ( int j = N; j >= 0; --j ){//分配的關系數 for ( int k = 0; k <= j; ++k ){//背包—— f[x][j][1] = max( f[x][j][1], f[x][j - k][1] + max( k == 0 ? -INF : f[to[i]][k - 1][1], f[to[i]][k][0] ) ); f[x][j][0] = max( f[x][j][0], f[x][j - k][0] + max( f[to[i]][k][1], f[to[i]][k][0] ) ); } } } for ( int i = 0; i <= N; ++i ) f[x][i][1] += c[x];//若取這個節點,加上這個點的價值 } int main(){ scanf( "%d%d", &N, &X ); for ( int i = 1; i <= N; ++i ){ scanf( "%d%d", &c[i], &t ); Add( i, t ); Add( t, i );//鏈式前向星存邊 } DFS( 0, -1 ); int ans(N); while( ans >= 0 ){ if ( f[0][ans][0] >= X ) break; ans--; } printf( "%d\n", ans ); return 0; }
[BZOJ1722] [Usaco2006 Mar] Milk Team Select產奶比賽 解題報告