zoukankan      html  css  js  c++  java
  • 【题解】[CQOI2005] 珠宝

    题目信息

    题目来源:CCF 重庆省选 2005;

    在线评测地址:Luogu#5765

    运行限制:时间 (1.00 extrm{s}),空间 (128 extrm{MiB})

    (笔者没有在网上找到原题面,于是以下采用的是洛谷的精简题面)

    题目描述

    有一棵 (n) 个结点的树,给每个点安排一个正整数编号,使得相邻点具有不同的编号,编号的总和尽量小。

    输入格式

    第一行一个整数 (n)

    以下 (n-1) 行,每行两个数 (u,v),表示 (u)(v) 间有一条边。

    输出格式

    仅一行,为最小编号和。

    数据规模与约定

    • 对于 (20\%) 的数据,(nle 10)
    • 对于 (40\%) 的数据,(nle 10^3)
    • 对于 (100\%) 的数据,(1le nle 5 imes 10^4)

    保证 (1le u,vle n)

    分析

    比较显然的树形 DP。(当时学树形 DP 的第一道例题就是这一个)

    树上的问题通常要强行定根,然后进行 BFS 确定 DP 顺序,接下来进行 DP。这道题转移时要注意考虑这个节点的权值及其孩子的权值的可能性。

    定义 (f_{i,j}) 为第 (i) 个点的权值为 (j) 时的最小值,则可以得到 (f_{i,j}=v_{i,j} + sumlimits_{i ightarrow p} min_{v=0}^{v eq j} f_{p,v})

    接下来的问题是 (j) 的上界,这将会直接影响到复杂度。经试验开到 (4) 即可。

    注意事项

    注意 BFS 完后要倒序DP。

    Code

    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    constexpr int max_n = 50000, max_v = 4;
    struct node // 队列节点
    {
    	int id, fa;
    
    	node(int _i = 0, int _f = -1) : id(_i), fa(_f) { }
    };
    
    int dp[max_n][max_v], hd[max_n], des[max_n<<1], nxt[max_n<<1], e_cnt = 0;
    node que[max_n];
    
    void add_edge(int s, int t)
    {
    	des[e_cnt] = t;
    	nxt[e_cnt] = hd[s];
    	hd[s] = e_cnt++;
    }
    
    int main()
    {
    	memset(hd, -1, sizeof(hd));
    
    	int n, ta, tb, ql = 0, qr = 0;
    	node cur;
    
    	scanf("%d", &n);
    	for (int i = 1; i < n; i++) // 输入,建图
    	{
    		scanf("%d%d", &ta, &tb);
    
    		add_edge(ta - 1, tb - 1);
    		add_edge(tb - 1, ta - 1);
    	}
    
    	que[qr++] = node();
    
    	while (ql < qr) // BFS
    	{
    		cur = que[ql++];
    
    		for (int p = hd[cur.id]; p != -1; p = nxt[p])
    			if (des[p] != cur.fa)
    				que[qr++] = node(des[p], cur.id); // 防止死循环,加上判断
    	}
    
    	for (int i = n - 1; i >= 0; i--)
    		for (int j = 0; j < max_v; j++) // 第一重遍历
    		{
    			dp[que[i].id][j] = j;
    
    			for (int p = hd[que[i].id]; p != -1; p = nxt[p])
    			{
    				ta = max_v * max_n;
    
    				for (int k = 0; k < max_v; k++) // 第二重遍历
    					if (j != k)
    					{
    						if (dp[des[p]][k] < ta) // 更小就更新
    							ta = dp[des[p]][k];
    					}
    				
    				dp[que[i].id][j] += ta;
    			}
    		}
    	
    	ta = max_v * max_n;
    	for (int i = 0; i < max_v; i++) // 统计答案
    		if (dp[0][i] < ta)
    			ta = dp[0][i];
    	
    	printf("%d
    ", ta); // 输出
    
    	return 0; // 然后就 AC 了、
    }
    
  • 相关阅读:
    es6箭头函数
    es6数组必看太实用了
    对象和数组的解构以及数组的遍历4种写法
    es6 map数据类型,要比set还很多
    es6中对象的一些操坐
    class类
    webStorm配置es6转es5
    gulp-babel,es6转es5
    jquery扩展插件,让demo元素也可以resize
    【leetcode刷题笔记】Remove Nth Node From End of List
  • 原文地址:https://www.cnblogs.com/5ab-juruo/p/solution-cqoi2005_lg5765.html
Copyright © 2011-2022 走看看