标签:ios 很多 eof 并且 amp 复杂度 ring 代码 sizeof
动态规划$+$容斥原理:
1、暴力状压
我们尝试设计状态:$$f[i][j][S]$$
表示新的图上点$i$对应旧的图上点$j$并且所有点的状态为一个二进制数$S$时的方案数
但是这样做为什么说是暴力呢。。。一看就知道,复杂度爆炸,然而我并不会证$qwq$
2、正解(可能吧):容斥原理
我们思考上面这种方法为什么会爆炸,就是因为有了最后那维状态,如果我们可以省去那个状态的话,就可以降低时间复杂度了,于是我们设:
$$f[i][j]$$表示新的图上点$i$对应旧的图上点$j$时的方案数
那么我们就面临一个问题,就是有很多重复的状态我们都算进来了,那么我们就考虑用容斥原理就好啦
我们发现只要集合长度:$|S|=n$时的方案数减去$|S|=n-1$时的方案数加上$|S|=n-2$时的方案数减去$|S|=n-3$时的方案数$......$
一加一减就阔以了
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define N 19
#define M 140
using namespace std;
struct Edge
{
int to,nxt;
}edge[N<<1];
int n,m,cnt;
ll ans;
int ban[N],head[N],g[N][N];
ll f[N][N];
void Add(int u,int v)
{
edge[++cnt]=(Edge){v,head[u]};
head[u]=cnt;
}
void Dfs(int u,int fa)
{
for(int i=1;i<=n;++i)
f[u][i]=1;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==fa)
continue;
Dfs(v,u);
for(int j=1;j<=n;++j)
{
ll sum=0;
for(int k=1;k<=n;++k)
sum+=f[v][k]*(g[k][j]&&ban[j]&&ban[k]);
f[u][j]*=sum;
}
}
}
signed main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
g[u][v]=g[v][u]=1;
}
for(int i=1;i<n;++i)
{
int u,v;
scanf("%d%d",&u,&v);
Add(u,v);
Add(v,u);
}
for(int i=0;i<(1<<n);++i)
{
memset(ban,0,sizeof(ban));
ll ret=0;
int size=n,now=i;
for(int j=1;now;now>>=1,++j)
ban[j]=(now&1),size-=(now&1);
// for(int j=1;j<=n;++j)
// printf("%d ",ban[j]);
// printf("\n");
Dfs(1,0);
for(int j=1;j<=n;++j)
ret+=f[1][j];
if(size%2)
ans-=ret;//printf("%d\n",ans);
else
ans+=ret;
}
printf("%lld",ans);
return 0;
}
标签:ios 很多 eof 并且 amp 复杂度 ring 代码 sizeof
原文地址:https://www.cnblogs.com/yexinqwq/p/10254401.html