NC204418 新集合

题目链接

题目

题目描述

集合 s 中有整数 1n ,牛牛想从中挑几个整数组成一个新的集合。

现在牛妹给牛牛加了 m 个限制 ,每个限制包含两个整数 uv ( uv),且 uv 不能同时出现在新集合中 。

请问牛牛能组成的新集合多少种。

可以选 0 个数。

返回一个整数,即新集合的种类数。

示例1

输入

3,2,[(1,2),(2,3)]

返回值

5

说明

当 n = 3 时,共有 8 个子集,当加上限制 (1, 2), (2, 3) 后,合法的自己有 [],[1],[2],[3],[1,3] 共 5 个

备注

第一个参数为 n 。第二个参数为 m 。第三个参数为 m 对 (u, v) 。1<n201m4001u,vn

题解

知识点:DFS。

一道计数题,用dfs比较合适。

有两种枚举方式:

  1. dfs的第 i 层枚举集合中第 i 个放的数字,如果能放立刻加一,为了保证不重复,我们每次都放比上一次大的数。

  2. dfs第 i 层枚举第 i 个数字”放“和“不放“进集合,每次能放的时候选择放可以加一,选择不放则不加。

两者dfs的区别在于,前者每次都放一个新的数字,一定能确定一个新的状态,没有搜索节点是被浪费的;后者因为只有对某个数字选择”放“的时候才会确定一个新状态,而选择“不放”则继承上一层状态不能确定一个新的状态,需要枚举完 n 个数字才能遍历所有可能状态。显然,前者的复杂度更优秀。

时间复杂度 O(2n)

空间复杂度 O(n+m)

代码

#include <bits/stdc++.h>
using namespace std;
struct Point {
int x, y;
};
int cnt;
bool vis[27];
void dfs(int n, vector<Point> &limit, int pos = 0) {
for (int i = pos + 1;i <= n;i++) {
bool ok = true;
for (int j = 0;j < limit.size();j++) {
if (limit[j].x == i && vis[limit[j].y]) ok &= false;
if (limit[j].y == i && vis[limit[j].x]) ok &= false;
}
if (ok) {
cnt++;
vis[i] = 1;
dfs(n, limit, i);
vis[i] = 0;
}
}
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
vector<Point> limit;
for (int i = 0;i < m;i++) {
int u, v;
cin >> u >> v;
limit.push_back({ u,v });
}
dfs(n, limit);
cout << cnt + 1 << '\n';
return 0;
}
posted @   空白菌  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示