第一眼看到题比较裸的状压dp就是f[i][j][s]表示考虑到第i个点,连了j条边,i和i左边k个点奇偶性状态为s的方案数,然后枚举i和谁连边向j+1转移,每个s再向i+1转移。
写完后发现这个做法有bug,因为同一个状态因为i向外连边的顺序不同而被重复记数了。比如:
第一个状态就在第四个状态中被重复记了两次,所以我们在加一位状态l,表示i正准备和i-l连边,这样i的边就是从左往右连的,就不会重复记数了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int p = 1000000007; 7 int n,m,k; 8 int f[35][35][1<<10][10]; 9 int main() 10 { 11 scanf("%d%d%d",&n,&m,&k); 12 f[1][0][0][1]=1; 13 for(int i=1;i<=n;i++) 14 { 15 for(int j=0;j<=m;j++) 16 { 17 for(int s=0;s<1<<(k+1);s++) 18 { 19 for(int l=1;l<=k;l++) 20 { 21 int tmp=f[i][j][s][l]; 22 f[i][j][s][l+1]+=tmp%=p; 23 if(l<=i-1)f[i][j+1][s^(1<<k)^(1<<(k-l))][l]+=tmp%=p; 24 } 25 if((s&1)==0)f[i+1][j][s>>1][1]+=f[i][j][s][k]%=p; 26 } 27 } 28 } 29 printf("%d ",f[n][m][0][k]); 30 return 0; 31 }