CF53E Dead Ends - 2500
题目思路
状压 dp。
设 $f_{S,T} $ 中 \(S\) 表示已经有多少点连通,\(T\) 表示 \(S\) 中哪些是终点(Dead Ends 神秘翻译,我觉得 ChatGPT 翻译成“死胡同”更好)。
假定每一次转移完新的 \(T\)(记为 \(nT\))中最大的点一定是当前加入的点,这样就能防止重复计数。
具体来说:
if(((nT>>(j-1))^1)==0) f[nS][nT]+=f[S][T];
这个判断条件其实就是在说第 \(j\) 位是 \(1\),并且比 \(j\) 更高的位全是 \(0\)。
AC Code
#include<bits/stdc++.h>
using namespace std;
const int N=11;
int f[1<<N][1<<N],n,m,k,G[N][N],ans;
int count(int x){
return __builtin_popcount(x);
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m>>k;
for(int i=1,u,v;i<=m;i++){
cin>>u>>v;
G[u][v]=G[v][u]=1;
int S=(1<<(u-1))+(1<<(v-1));
f[S][S]=1;
}
for(int S=0;S<(1<<n);S++){
if(count(S)<2) continue;
for(int T=S;T;T=(T-1)&S){
if(!f[S][T]||count(T)<2) continue;
for(int i=1;i<=n;i++){
if(((S>>(i-1))&1)==0) continue;
for(int j=1;j<=n;j++){
if(((S>>(j-1))&1)||!G[i][j]) continue;
int nS=S|(1<<(j-1)),nT=((T>>(i-1))&1?T^(1<<(i-1))^(1<<(j-1)):T^(1<<(j-1)));
if(((nT>>(j-1))^1)==0) f[nS][nT]+=f[S][T];
}
}
}
}
for(int T=0;T<(1<<n);T++){
if(count(T)==k) ans+=f[(1<<n)-1][T];
}
cout<<ans;
return 0;
}
/*
状压点,但是条件和边有关
f[2^10][2^10] 有多少点已连通,有哪些点是终点。
运算优先级也是非常恶心
*/
古顾故

浙公网安备 33010602011771号