lightoj1219Mafia

    对于某个节点u, 如果整个子树里的人数超过了节点数, 那么显然就要把多余的人移动到点u的父亲处, 而如果人不足, 就需要从u的父亲处拿人过来, 至于u父亲出人够不够, 那么就需要考虑以u的父亲为根的子树了, 所以可以考虑dfs递归处理问题, 对于所有节点, 如果节点上人太多, 多余的人必然要到他父亲那边, 如果没人,必要要从父亲处要人, 所以在每次处理完一颗子树时,根据子树的根的情况, 来修改子树根的父亲的情况即可

    // #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <iostream>
    #include <algorithm>
    #include <iomanip>
    #include <sstream>
    #include <string>
    #include <stack>
    #include <queue>
    #include <deque>
    #include <vector>
    #include <map>
    #include <set>
    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    #include <stdlib.h>
    #include <limits.h>
    // #define DEBUG
    #ifdef DEBUG
    #define debug(...) printf( __VA_ARGS__ )
    #else
    #define debug(...)
    #endif
    #define MEM(x,y) memset(x, y,sizeof x)
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> ii;
    const int inf = 1 << 30;
    const int INF = 0x3f3f3f3f;
    const int MOD = 1e9 + 7;
    bool vis[10010];
    int moves;
    int n;
    vector<int> G[10010];
    int have[10010];
    int solve(int u){
    	vis[u] = true;
    	int sum = have[u] - 1;
    	for (int i = 0;i < G[u].size();++i){
    		int v = G[u][i];
    		if (vis[v]) continue;
    		int w = solve(v);
    		sum += w;//u节点为根的树还需要多少人;
    		moves += abs(w);
    	}
    	return sum;
    }
    int main()
    {	
    	// freopen("in.txt","r",stdin);
    	// freopen("out.txt","w",stdout);
    	int icase = 0, t;
    	cin >> t;
    	while(t--){
    		cin >> n;
    		for (int i = 1;i <= n;++i)
    			G[i].clear();
    		memset(vis, false,sizeof vis);
    		for (int i = 1;i <= n;++i){
    			int u, w, num;
    			scanf("%d%d%d",&u, &w, &num);
    			have[u] = w;
    			int v;
    			while(num--){
    				cin >> v;
    				G[u].push_back(v);
    				G[v].push_back(u);
    			}
    		}
    		moves = 0;
    		solve(1);
    		printf("Case %d: %d\n", ++icase, moves);
    	}
    	return 0;
    }
    


你可能感兴趣的:(贪心,lightoj,树形DP)