原来蒙德里安的梦想和最短路径是两个状压的套路题型....蒟蒻落泪
考察:状压dp
思路:
参考蒙德里安的梦想,本题如果i行的摆放只与i-1行有关.也就是说设i-1行的摆放情况为a,i行为b.要满足这些条件:a&b=0,a无连续1,b无连续1,a|b无连续1.
预处理合法的状态.再枚举合法的可转化状态.再套模板即可
注意: 答案是long long
需要定义三维状态f[i][j][k]分别表示第i行,第i行的状态j,放了k个国王.
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <vector> 6 using namespace std; 7 typedef long long ll; 8 typedef vector<int> VI; 9 const int N = 11; 10 int n,k,cnt[1<<N]; 11 bool st[1<<N]; 12 VI v[1<<N]; 13 ll f[N][1<<N][N*N]; 14 void inits() 15 { 16 f[0][0][0] = 1; 17 for(int i=0;i<1<<n;i++) 18 { 19 int cnt = 0; 20 for(int j=0;j<n;j++) 21 { 22 if(i>>j&1) cnt++; 23 else cnt = 0; 24 if(cnt>1) break; 25 } 26 if(cnt>1) st[i] = 0; 27 else st[i] = 1; 28 } 29 for(int i=0;i<1<<n;i++) 30 for(int j=0;j<1<<n;j++) 31 if(st[j]&&st[i]&&(i&j)==0&&st[i|j]) v[i].push_back(j); 32 for(int i=0;i<1<<n;i++) 33 for(int j=0;j<n;j++) 34 if(i>>j&1) cnt[i]++; 35 } 36 int main() 37 { 38 ll ans = 0; 39 scanf("%d%d",&n,&k); 40 inits(); 41 for(int i=1;i<=n;i++) 42 for(int j=0;j<1<<n;j++) 43 if(st[j]) 44 for(int t=cnt[j];t<=k;t++) 45 for(auto it:v[j]) 46 f[i][j][t] += f[i-1][it][t-cnt[j]]; 47 for(int i=0;i<1<<n;i++) 48 ans+=f[n][i][k]; 49 printf("%lld\n",ans); 50 return 0; 51 }