首页 > 其他分享 >CF1929E 题解

CF1929E 题解

时间:2024-02-17 15:13:49浏览次数:31  
标签:dth int 题解 路径 dfs CF1929E include dp

题意:

给定一棵 \(n\) 个节点数和 \(k\) 条路径 \((a_i, b_i)\),求至少将多少条边染色,使得给定路径都至少有一条染色的边。

\(n \le 10^5, k \le 20\)。

思路:

好题。

显然状压 \(dp\),\(dp[S]\) 表示至少染多少条边使得 \(S\) 中的路径都满足条件。正常思路是枚举子集转移,考虑 \(T \sub S\) 能否有一条边同时经过 \(T\) 中所有路径,但是这样是 \(O(3^n)\) 的。

考虑建出这 \(2k\) 个点的虚树,我们定义 \(V_i\) 表示第 \(i\) 条边经过的所有路径,结合虚树的知识,不难发现本质不同的 \(V_i\) 是 \(O(k)\) 的。

于是我们考虑用这些转移,采用刷表法,写成 \(dp[S | v_i] = min(dp[S | v_i], dp[S] + 1)\),这样时间复杂度就是 \(O(k2^k)\) 的了。

点击查看代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5;

int n, k;
vector<int> e[N];

int d[N] = {0};
int p[N] = {0};

void dfs(int x, int pr, int dth) {
	p[x] = pr, d[x] = dth;
	for (auto i: e[x])
		if (i != pr)
			dfs(i, x, dth + 1);
}

int val[N] = {0};
 
void upd(int a, int b, int v) {
	if (a == b)	
		return;
	if (d[a] < d[b])
		swap(a, b);
	val[a] += v;
	upd(p[a], b, v);
}
 
int dp[(1 << 20) + 5] = {0};
 
void slv() {
	cin >> n;
	for (int i = 1; i <= n; i++)
		val[i] = 0, e[i].clear();
	for (int i = 1, u, v; i < n; i++) {
		cin >> u >> v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs(1, 1, 1);
	cin >> k;
	for (int i = 1, a, b; i <= k; i++) {
		cin >> a >> b;
		upd(a, b, (1 << (i - 1)));
	}
	sort(val + 1, val + n + 1);
	int cur = unique(val + 1, val + n + 1) - val - 1;
	
	for (int S = 0; S < (1 << k); S++) 
		dp[S] = 2e9;
	dp[0] = 0;
	for (int S = 0; S < (1 << k); S++)
		for (int i = 1; i <= cur; i++)
			dp[(S | val[i])] = min(dp[(S | val[i])], dp[S] + 1);
	cout << dp[(1 << k) - 1] << endl;
}

int main() {
	int T;
	cin >> T;
	while (T--)
		slv();
	return 0;
} 

标签:dth,int,题解,路径,dfs,CF1929E,include,dp
From: https://www.cnblogs.com/rlc202204/p/18017976

相关文章

  • 整数划分 题解
    题目描述如何把一个正整数N(N长度<20)划分为M(M>1)个部分,使这M个部分的乘积最大。N、M从键盘输入,输出最大值及一种划分方式。输入格式第一行一个正整数T(T<=10000),表示有T组数据。接下来T行每行两个正整数N,M。输出格式对于每组数据第一行输出最大值。第二行输出划分方案,将N按......
  • 情书密码 题解
    题目描述有消息称:绝恋找到了自己的MissRight,正准备自己的表白。绝恋已经写好了情书,但为了避免其它人截获,他对情书进行加密。为了打探绝恋的私密,你冒着生命危险终于搞到了这封情书。原以为可以轻易将情书解密,结果竟然发现聪明的绝恋并没有直接写出加密用的密码,而是在那粉红色的......
  • CF484B题解
    朴素的办法是枚举每两个数然后更新取模的结果。时间复杂度为\(O(n^2)\)不能通过。这个朴素的过程可以看作枚举一个数然后找对其取模最大值的过程。我们可以枚举一个数,然后再枚举以它的倍数为两端的区间,找其中取模的最大值。找最大值的过程可以二分或双指针。值域很小,也可以......
  • 牛客小白87题解A-G
    A小苯的石子游戏本题贪心模拟即可B小苯的排序疑惑考虑到最简单的操作把n-1个数排好,最后一个看能否有序。即:a[1]<=min(a[2],a[3],a[4]..,a[n])||a[n]>=max(a[1],a[2],a[3]....,a[n-1])满足条件,反之易得不可能C&D小苯的IDE括号问题本题考察题意理解,简单版本我们可以只关注逻......
  • 0217-0224校赛部分题解
    SMUWinter2024Round#3(Div.2)对于自己比较有价值的题目是D题https://codeforces.com/gym/102897/problem/D?mobile=trueJ题https://codeforces.com/gym/102897/problem/JK题https://codeforces.com/gym/102897/problem/KE题https://codeforces.com/gym/102897/prob......
  • 关于thrift python接口和java通信出现问题解决
    真的无语,搞了一个下午。使用thrift出现错误,先说一下遇到第一个错误,如下图:那时候代码是这叼样```if__name__=='__main__':handler=MessageServiceHandler()processor=MessageService.Processor(handler)transport=TSocket.TServerSocket(None,"9090"......
  • P3157 [CQOI2011] 动态逆序对 题解
    题目链接:动态逆序对常见经典题,理解一个数对逆序对贡献计算即可。对于一个数而言,它在一个序列中的逆序对有两部分贡献,一部分为前面比它严格大的数,另一部分为后面比它严格小的数,有道二莫题也是基于此去考虑的。考虑最开始知道了总逆序数,每次删除一个数逆序数会减少两部分值,显然就......
  • 选课 题解
    题目描述大学里实行学分。每门课程都有一定的学分,学生只要选修了这门课并考核通过就能获得相应的学分。学生最后的学分是他选修的各门课的学分的总和。每个学生都要选择规定数量的课程。其中有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其它的一些课程的基础上才......
  • 洛谷 P4065 题解
    模拟赛T1,纪念一下第一次场切紫。(话说场上这么多人切是不是都找到原了,就我这么傻想了半天)正难则反,很容易的将题目转化为选择若干种颜色,使这些颜色在原数组中的位置连续。设$pre_i$为颜色$i$最早出现的位置,$suf_i$为颜色$i$最晚出现的位置。假设通过选择若干颜色得到的位......
  • P10149 [Ynoi1999] XM66F题解
    题解首先,问题是静态的区间查询问题,一眼莫队。那么我们就需要考虑所需要维护的内容在区间扩增或者缩减时的变化如何快速维护。我们可以先写出对于区间\([l,r]\)来说,满足\(l\lei<j<k\ler\)的有序三元组\((i,j,k)\)数量的表达式,方便拆式子:\[\sum\limits_{i=l}^{r}......