【题解】P3349 [ZJOI2016]小星星 - 子集dp - 容斥
P3349 [ZJOI2016]小星星
声明:本博客所有题解都参照了网络资料或其他博客,仅为博主想加深理解而写,如有疑问欢迎与博主讨论✧。٩(ˊᗜˋ)و✧*。
题目描述
小 \(Y\) 是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品。她有 \(n\) 颗小星星,用 \(m\) 条彩色的细线串了起来,每条细线连着两颗小星星。
有一天她发现,她的饰品被破坏了,很多细线都被拆掉了。这个饰品只剩下了 \(n-1\) 条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树。小 \(Y\) 找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星。如果现在饰品中两颗小星星有细线相连,那么要求对应的小星星原来的图纸上也有细线相连。小 \(Y\) 想知道有多少种可能的对应方式。
只有你告诉了她正确的答案,她才会把小饰品做为礼物送给你呢。
输入格式
第一行包含个 \(2\) 正整数 \(n,m\),表示原来的饰品中小星星的个数和细线的条数。接下来 \(m\) 行,每行包含 \(2\) 个正整数 \(u,v\),表示原来的饰品中小星星 \(u\) 和 \(v\) 通过细线连了起来。这里的小星星从 \(1\) 开始标号。保证 \(u≠v\),且每对小星星之间最多只有一条细线相连。接下来 \(n-1\) 行,每行包含个 \(2\) 正整数 \(u,v\),表示现在的饰品中小星星 \(u\) 和 \(v\) 通过细线连了起来。保证这些小星星通过细线可以串在一起。\(n<=17,m<=n*(n-1)/2\)
输出格式
输出共 \(1\) 行,包含一个整数表示可能的对应方式的数量。如果不存在可行的对应方式则输出 \(0\)。
\(Solution\)
从一个暴力开始考虑,设 \(f[i][j][S]\) 表示,以 \(i\) 为树根的子树,当 \(i\) 映射到 \(j\) 上,映射的子集为 \(S\) 时的方案数。
不断合并 \(i\) 的子树来转移,复杂度貌似是 \(O(3^n n)\) 的,但是不知道为什么 \(emm\)
考虑如何优化
如果我们去除 \(S\) 这一维,那么答案中会有一些不合法的情况,但这些不合法的情况仅为多个点映射到同一个点,不会出现两个点之间没有边相连的情况
于是我们可以做容斥,去除掉这些不合法情况
首先枚举删除一个点,在剩下的图上做一遍 \(f[i][j]\) 的 \(dp\),此时找到的状态至少有两个点映射在了同一个点上(因为图上只有 \(n - 1\) 个点,而树上有 \(n\) 个)
我们把这些状态都删除,但是会发现,会重复删除掉三个点,四个点等映射在同一个点上的情况,于是再加上它们
然后就可以做容斥了
\(Code\)
代码其实挺简单的,但是要注意在做 \(dp\) 的时候,把儿子循环放外面,先做儿子的 \(dp\) 再枚举 \(j\),不然会超时(不过这个逻辑应该挺简单,我真是降智了)
#include<bits/stdc++.h>
#define ll long long
#define F(i, x, y) for(int i = x; i <= y; ++i)
using namespace std;
int read();
const int N = 400;
int n, m;
int mp[N][N];
int head[N], cnt, ver[N], next[N];
ll ban[N], f[N][N];
ll ans;
void add(int x, int y)
{
ver[++ cnt] = y, next[cnt] = head[x], head[x] = cnt;
}
void dfs(int x, int fa)
{
F(j, 1, n) f[x][j] = 1;
for(int i = head[x]; i; i = next[i])
if(ver[i] != fa)
{
dfs(ver[i], x);
F(j, 1, n)
if(! ban[j])
{
ll res = 0;
F(v, 1, n) if(! ban[v]) res += f[ver[i]][v] * mp[v][j];
f[x][j] *= res;
}
}
}
int main()
{
n = read(), m = read();
for(int i = 1, u, v; i <= m; ++ i) u = read(), v = read(), mp[u][v] = mp[v][u] = 1;
for(int i = 1, u, v; i <= n - 1; ++ i) u = read(), v = read(), add(u, v), add(v, u);
F(k, 0, (1 << n) - 1) // 可以直接枚举状态,不用按顺序,这样简单很多
{
F(i, 1, n) ban[i] = 0;
F(i, 1, n) F(j, 1, n) f[i][j] = 0;
int size = 0; ll res = 0;
for(int i = 1, s = k; s; ++ i, s >>= 1) if(s & 1) ban[i] = 1, ++ size;
dfs(1, 0);
F(i, 1, n) res += f[1][i];
if(size & 1) ans -= res;
else ans += res;
}
printf("%lld\n", ans);
return 0;
}
int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
【题解】P3349 [ZJOI2016]小星星 - 子集dp - 容斥的更多相关文章
- bzoj 4455 [Zjoi2016]小星星 树形dp&容斥
4455: [Zjoi2016]小星星 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 643 Solved: 391[Submit][Status] ...
- uoj185 [ZJOI2016]小星星 【dp + 容斥】
题目链接 uoj185 题解 设\(f[i][j]\)表示\(i\)为根的子树,\(i\)号点对应图上\(j\)号点时的方案数 显然这样\(dp\)会使一些节点使用同一个节点,此时总的节点数就不满\( ...
- 洛谷 P3349 [ZJOI2016]小星星 解题报告
P3349 [ZJOI2016]小星星 题目描述 小\(Y\)是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有\(n\)颗小星星,用\(m\)条彩色的细线串了起来,每条细线连着两颗小星星. 有一 ...
- bzoj 3622 DP + 容斥
LINK 题意:给出n,k,有a,b两种值,a和b间互相配对,求$a>b$的配对组数-b>a的配对组数恰好等于k的情况有多少种. 思路:粗看会想这是道容斥组合题,但关键在于如何得到每个a[ ...
- 【BZOJ 4665】 4665: 小w的喜糖 (DP+容斥)
4665: 小w的喜糖 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 94 Solved: 53 Description 废话不多说,反正小w要发喜 ...
- [Luogu P1450] [HAOI2008]硬币购物 背包DP+容斥
题面 传送门:https://www.luogu.org/problemnew/show/P1450 Solution 这是一道很有意思的在背包里面做容斥的题目. 首先,我们可以很轻松地想到暴力做背包 ...
- P3160 [CQOI2012]局部极小值 题解(状压DP+容斥)
题目链接 P3160 [CQOI2012]局部极小值 双倍经验,双倍快乐 解题思路 存下来每个坑(极小值点)的位置,以这个序号进行状态压缩. 显然,\(4*7\)的数据范围让极小值点在8个以内(以下示 ...
- [BZOJ 1042] [HAOI2008] 硬币购物 【DP + 容斥】
题目链接:BZOJ - 1042 题目分析 首先 Orz Hzwer ,代码题解都是看的他的 blog. 这道题首先使用DP预处理,先求出,在不考虑每种硬币个数的限制的情况下,每个钱数有多少种拼凑方案 ...
- BZOJ.2655.calc(DP/容斥 拉格朗日插值)
BZOJ 洛谷 待补.刚刚政治会考完来把它补上了2333.考数学去了. DP: 首先把无序化成有序,选严格递增的数,最后乘个\(n!\). 然后容易想到令\(f_{i,j}\)表示到第\(i\)个数, ...
随机推荐
- algorithm++:一个整数称为是:【幸运数】,如果这个整数的各位数字的平方和为1或者反复计算各位数字的平方和为1 例如 19 是个幸运数
1):一个整数称为是:[幸运数],如果这个整数的各位数字的平方和为1或者反复计算各位数字的平方和为1 例如 19 是个幸运数 coding:java程序实现 import org.junit.Test ...
- 上传到码云时遇到:Incorrect username or password ( access token )
由于之前上传到 码云时候使用命令:git push -u origin master时出现如下bug Incorrect username or password ( access token ) 时 ...
- nosql Redis命令操作详解
Redis命令操作详解 一.key pattern 查询相应的key (1)redis允许模糊查询key 有3个通配符 *.?.[] (2)randomkey:返回随机key (3)type key: ...
- 少儿编程崛起?2020年4月编程语言排名发布——Java,C,Python分列前三,Scratch挤进前20
前三并没有什么悬念,依然是Java,C,Python.C与Java的差距正在缩小,不过我们不用担心,在大数据分析领域Java,Python依然都是不可或缺的. 基于图形的基于块的编程语言Scratch ...
- LLVM 编码规范 - 中文翻译
LLVM 编码规范 导论 语言.库和标准 C++ 标准版本 C++ 标准库 Go 代码准则 机械的代码问题 代码格式化 注释 头文件 类概述 method information 注释格式化 使用Do ...
- Spring的IOC容器学习笔记
(一)Spring的IOC学习 在applicationContext.xml来配置bean,通过该接口,在主程序中,可以指定初始化的对象,不需要在进行赋值操作,直接在xml里配置好. 接下来分享的是 ...
- SQL Server中STATISTICS IO物理读和逻辑读的误区
SQL Server中STATISTICS IO物理读和逻辑读的误区 大家知道,SQL Server中可以利用下面命令查看某个语句读写IO的情况 SET STATISTICS IO ON 那么这个命令 ...
- 多线程学习笔记(四)---- Thread类的其他方法介绍
一.wait和 sleep的区别 wait可以指定时间也可以不指定时间,而sleep必须指定时间: 在同步中时,对cpu的执行权和锁的处理不同: wait:释放执行权,释放锁:释放锁是为了别人noti ...
- LeetCode | 1013. 将数组分成和相等的三个部分
给定一个整数数组 A,只有我们可以将其划分为三个和相等的非空部分时才返回 true,否则返回 false. 形式上,如果我们可以找出索引i+1 < j且满足(A[0] + A[1] + ... ...
- 字符串截取及切割,正则表达式,expect预期交互
字符串截取及切割,正则表达式,expect预期交互 案例1:字符串截取及切割 案例2:字符串初值的处理 案例3:expe ...