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] 有多少点已连通,有哪些点是终点。

运算优先级也是非常恶心 
*/
posted @ 2026-08-25 10:45  深申  阅读(15)  评论(0)    收藏  举报