• 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;
    }
    

      

  • 相关阅读:
    Redis学习手册(实例代码)
    来博客园一年了
    Redis学习手册(管线)
    Redis学习手册(持久化)
    Redis学习手册(目录)
    在博客园的第100篇博客
    Redis学习手册(主从复制)
    Redis学习手册(内存优化)
    JS弹出模式提示窗体,实现页面其他地方不可编辑效果
    prototype属性使用说明
  • 原文地址:https://www.cnblogs.com/td15980891505/p/5798854.html
Copyright © 2020-2023  润新知