ZJOI2016 小星星
标签:子集反演,动态规划
[ZJOI2016]小星星
题目描述
小 Y 是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品。她有
有一天她发现,她的饰品被破坏了,很多细线都被拆掉了。这个饰品只剩下了
对于
思路点拨
在这之前,你需要知道子集反演的一种形式.我们定义
回到这道题目,由于给树上节点编号的限制是一个排列,这不好解,所以我们可以子集反演变成可以给树上节点随便编号,只要使用地编号在集合
我们定义状态
容易看出这是
时空复杂度计算:时间
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-f;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int MAXN=18;
int n,m;
bool vis[MAXN][MAXN];
vector<int> e[MAXN];
int f[MAXN][MAXN];
int s[MAXN],top;
void dfs(int x,int dad){
for(int i=1;i<=top;i++)
f[x][s[i]]=1;
for(int i=0;i<e[x].size();i++){
int to=e[x][i];
if(to==dad) continue;
dfs(to,x);
for(int i=1;i<=top;i++){
int cnt=0;
for(int j=1;j<=top;j++)
if(vis[s[i]][s[j]])
cnt+=f[to][s[j]];
f[x][s[i]]*=cnt;
}
}
}
signed main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int u=read(),v=read();
vis[u][v]=vis[v][u]=1;
}
for(int i=1;i<n;i++){
int u=read(),v=read();
e[u].push_back(v);
e[v].push_back(u);
}
int ans=0;
for(int i=1;i<(1<<n);i++){
memset(f,0,sizeof(f));
top=0;
for(int j=0;j<n;j++)
if(i&(1<<j))
s[++top]=j+1;
dfs(1,-1);
int cnt=0;
for(int i=1;i<=top;i++)
cnt+=f[1][s[i]];
if((n-top)&1) ans-=cnt;
else ans+=cnt;
}
cout<<ans;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现