【题解】CF53E Dead Ends
0
EASY,完全独立开掉的紫题
1:数据范围
根据范围,考虑状压 \(DP\)
2:如何dp
如果 生成树集合 与 终点集合 相同,则它们是等价的
把他们压成状态
3:怎么转移
\(dp[S][G]:\) 生成树集合为 \(S\) ,终点集合为 \(G\),方案数
枚举非 \(S\) 集合中的点,再枚举 \(S\) 集合中的点,保证他们之间连边
由此重新计算 \(S,G\) 得到 \(S1,G1\) ,进行转移
4:修正
我们测样例的时候,发现过不了
而输出是样例的若干倍数
我们画图观察得到结论:
如果 \(dp[S][G]\) 中 \(G\) 有 \(x\) 个 \(1\) ,则 \(dp[S][G]\) 会被重复统计 \(x\) 次,需要除去
5:代码
#include<bits/stdc++.h>
using namespace std;
const int N=11;
int dp[1<<N][1<<N];
int mp[N][N];
int n,m,K;
int msiz(int x){
int res=0;
while(x){
res+=x&1;
x>>=1;
}
return res;
}
int main(){
cin>>n>>m>>K;
while(m--){
int a,b;cin>>a>>b;
a--;b--;
mp[a][b]=mp[b][a]=1;
}
dp[0][0]=1;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(i==j) continue;
if(mp[i][j]) dp[(1<<i)^(1<<j)][(1<<i)^(1<<j)]=2;
}
}
for(int S=0;S<(1<<n);S++){
for(int G=S;~G;G--){
G&=S;
if(dp[S][G]==0) continue;
if(msiz(G)) dp[S][G]/=msiz(G);
for(int i=0;i<n;i++){
if(S>>i&1) continue;
int S1=S^(1<<i);
for(int j=0;j<n;j++){
if(!mp[i][j]) continue;
if(!(S>>j&1)) continue;
int G1=G^(1<<i);
if(G1>>j&1) G1^=(1<<j);
dp[S1][G1]+=dp[S][G];
//cout<<"-->"<<S<<" "<<G<<" "<<S1<<" "<<G1<<" "<<dp[S1][G1]<<"\n";
}
}
}
}
int ans=0;
for(int G=0;G<(1<<n);G++){
if(msiz(G)==K){
ans+=dp[(1<<n)-1][G];
//cout<<(1<<n)-1<<" "<<G<<" "<<dp[(1<<n)-1][G]<<"\n";
}
}
cout<<ans<<"\n";
return 0;
}
6:反思
修正

浙公网安备 33010602011771号