zoukankan      html  css  js  c++  java
  • UVa 1218

    /*---UVa 1218 - Perfect Service
    ---首先对状态进行划分:
    ---dp[u][0]:u是服务器,则u的子节点可以是也可以不是服务器
    ---dp[u][1]:u不是服务器,但u的父节点是服务器,则u的所有儿子节点都不是服务器
    ---dp[u][2]:u和u的父亲都不是服务器,则u的儿子恰好有一个是服务器
    ---状态转移方程:
    ---dp[u][0]=sum{min(dp[v][0],dp[v][1])}+1
    ---dp[u][1]=sum(dp[v][2]);
    ---对于状态dp[u][2],计算略微复杂,这个状态说明u的儿子节点中恰好有一个是服务器,于是需要枚举每一个儿子节点是服务器
    ---剩下儿子不是服务器的情况,考虑到d(u,1)=sum(dp[v][2]),所以每次枚举时,不必再累加子节点不是服务器的情况,因为这样
    ---会使得计算一个节点复杂度达到O(k^2),k是u的子节点个数,可以:dp[u][2]=min(dp[u][1]-dp[v][2]+dp[v][0]),枚举v即可
    ---在实现时,首先递归的构造有根树。然后可以采用记忆化搜索。
    ---初始化问题,若u是叶子节点,dp[u][0]=1,dp[u][1]=0,dp[u][2]=INF,服务器个数不会超过10000,所以为了保准累加结果不溢出
    ---可以将INF设置为10000.
    */
    #define _CRT_SECURE_NO_DEPRECATE
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<vector>
    using namespace std;
    #define INF 10000+10;
    const int maxn = 10000 + 10;
    
    int d[maxn][3];
    int parent[maxn];
    vector<int>vec[maxn];
    
    //构造有根树
    void dfs(int u, int fa){
    	parent[u] = fa;
    	for (int i = 0; i < vec[u].size(); i++){
    		int v = vec[u][i];
    		if (v != fa) dfs(v, u);
    	}
    }
    
    int dp(int u, int k){
    	int&ans = d[u][k];
    	if (ans >= 0)return ans;
    	int n = vec[u].size();
    	if (k == 0)ans = 1;
    	else if (k == 1)ans = 0;
    	else ans = INF;
    	if (n == 1 && parent[u] == vec[u][0]){ //叶节点
    		return ans;
    	}
    	for (int i = 0; i < n; i++){
    		int v = vec[u][i];
    		if (v == parent[u])continue;  //v是u的父节点,则跳过
    		if (k == 0)ans += min(dp(v, 0), dp(v, 1));
    		else if (k == 1) ans += dp(v, 2);
    		else ans = min(ans, dp(u, 1) - dp(v, 2) + dp(v, 0));
    	}
    	return ans;
    }
    int main(){
    	int n, i,u,v;
    	while (scanf("%d", &n)){
    		for (i = 0; i <= n; i++)vec[i].clear();
    
    		for (i = 1; i < n; i++){
    			scanf("%d%d", &u, &v);
    			u--, v--;
    			vec[u].push_back(v);
    			vec[v].push_back(u);
    		}
    		scanf("%d", &v);
    		dfs(0, -1); 
    		vec[0].push_back(-1);
    		memset(d, -1, sizeof(d));
    		int ans = min(dp(0, 0), dp(0, 2));
    		printf("%d
    ", ans);
    		if (v == -1)break;
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    常见寻找OEP脱壳的方法
    Windows内核原理系列01
    HDU 1025 Constructing Roads In JGShining's Kingdom
    HDU 1024 Max Sum Plus Plus
    HDU 1003 Max Sum
    HDU 1019 Least Common Multiple
    HDU 1018 Big Number
    HDU 1014 Uniform Generator
    HDU 1012 u Calculate e
    HDU 1005 Number Sequence
  • 原文地址:https://www.cnblogs.com/td15980891505/p/5798854.html
Copyright © 2011-2022 走看看