/** * First, notice that the game-play given in the statement just * describes a DFS order, so the levels should be completed in * an order of DFS. * We will use dynamic programming to solve the problem. * dp[v][p] = (a, b) * Consider subtree of vertex 'v', Chef has already worked 'p' hours * during the first workday. 'a' is the minimal number of additional workdays * necessary to complete the whole subtree of vertex 'v' and 'b' is the * minimal number of hours Chef has to work on the last of (a + 1) workdays. * dp[root][h] is the answer * To compute the values of this dynamic programming we can use... * ... another dynamic programming :D * f[msk][p] = (a, b) * msk in a bitmask that describes some subset of vertex 'v' sons * Assume we have started in vertex 'v' and Chef has already worked 'p' hours * during first workday, after he has completed all the subtrees described by * 'msk'. The meaning of 'a' and 'b' here is the same as in dp[v][p]. * To calculate the second dynamic programming we can just extend the 'msk' by * one bit every time. Then dp[v][p] is just f[full mask][p]. **/ #include using namespace std; const int MX = 1000; int h, t[MX]; vector G[MX]; pair dp[MX][25]; void dfs(int v) { static pair f[1 << 10][25]; // first, calculate everything for all children for (int u : G[v]) dfs(u); int n = G[v].size(); // initalize f[][] with infinities for (int msk = 0; msk < (1 << n); msk++) for (int p = 0; p <= h; p++) f[msk][p] = make_pair(MX, h); // first of all we should complete level 'v' // we will put the time taken into the base state // of our second dp - f[0][p], that corresponds to // a state with none of the children completed // we have enough time on the first workday: for (int p = 0; p + t[v] <= h; p++) f[0][p] = make_pair(0, p + t[v]); // we don't have enough time on the first workday: for (int p = h + 1 - t[v]; p <= h; p++) f[0][p] = make_pair(1, t[v]); for (int msk = 0; msk < (1 << n); msk++) for (int i = 0; i < n; i++) if (((msk >> i) & 1) == 0) for (int p = 0; p <= h; p++) { // we have already completed all the subtrees // described by 'msk' and the next subtree will be 'i'. // the state right after we have finished all the // subtrees in 'msk' pair& a = f[msk][p]; // dp value that we want to update (after adding subtree) pair& b = f[msk | (1 << i)][p]; // time spent in newly added subtree, we will have // a.second hours worked on the first workday (the last // workday to complete all subtrees in 'msk') pair& c = dp[G[v][i]][a.second]; // overall we will spend (a.first + c.first) additional // workdays and will have worked exactly c.second hours // during the last one b = min(b, make_pair(a.first + c.first, c.second)); } // update values of global dp[][] using the values of second dp for (int p = 0; p <= h; p++) dp[v][p] = f[(1 << n) - 1][p]; } int main() { int T; scanf("%d", &T); while (T--) { int n; scanf("%d %d", &n, &h); for (int i = 0; i < n; i++) scanf("%d", t + i); for (int i = 0; i < n; i++) { G[i].clear(); int m; scanf("%d", &m); for (int j = 0; j < m; j++) { int x; scanf("%d", &x); G[i].push_back(x - 1); } } dfs(0); printf("%d\n", dp[0][h].first); } return 0; }