我好久都没有发博客了……
可不是因为我没做题啊,因为懒得发qwq……
今天发一波状压dp(就是dp)。
我还想不到如果不是格子图,状压dp怎么用……
因为它与dp的不同就是它可以用二进制来表示这一位(这个格子选不选)……
dp [ i ] [ j ] [ t ] 表示第 i 行,第 j 个状态,选择 t 个的方案数……
其实因为每一行都一样,所以其实所谓状态 j 就是第 j 种放法罢了,而第几行其实无所谓,因为每一行都一样。
当然一开始第1行,第 j 种状态,放第 j 种状态下应该放的数量的方案数自然是1。
接下来上代码:
#include<cstdio> #include<iostream> #include<vector> #include<cstring> #include<algorithm> using namespace std; #define int long long int dp[20][200][200],mark[200],uni[200],ans[200],sta[200]; vector<int> sec[900]; int n,k,tot; void dfs(int x) { if(x==n+1) { tot++; for(int i=1; i<=n; i++) { sta[tot]*=2; sta[tot]+=ans[i]; mark[tot]+=ans[i]; } return ; } ans[x]=0; dfs(x+1); if(!ans[x-1]) { ans[x]=1; dfs(x+1); ans[x]=0; } } bool ac(int l1,int l2) { for (int i = 2; i < n; i++) { if ((sta[l1] & uni[i]) && ((sta[l2] & uni[i - 1]) || (sta[l2] & uni[i]) || (sta[l2] & uni[i + 1]))) return 0; if ((sta[l2] & uni[i]) && ((sta[l1] & uni[i - 1]) || (sta[l1] & uni[i]) || (sta[l1] & uni[i + 1]))) return 0; } if( (sta[l1] & uni[1]) && ( (sta[l2] & uni[1]) || sta[l2] & uni[2] ) ) return 0; if( (sta[l1] & uni[n]) && ( (sta[l2] & uni[n]) || sta[l2] & uni[n-1]) ) return 0; if( (sta[l2] & uni[1]) && ( (sta[l1] & uni[1]) || sta[l1] & uni[2] ) ) return 0; if( (sta[l2] & uni[n]) && ( (sta[l1] & uni[n]) || sta[l1] & uni[n-1]) ) return 0; return 1; } main() { scanf("%lld%lld",&n,&k); if(n==0) { printf("0"); return 0; } if(n==1) { if(k==0) printf("1"); else printf("0"); return 0; } uni[n]=1; for(int i=n-1; i>=1; i--) uni[i]=uni[i+1]<<1; dfs(1); for(int i=1; i<=tot; i++) for(int j=1; j<=tot; j++) if(ac(i,j)) sec[i].push_back(j); for(int i=0; i<=tot; i++) dp[1][i][mark[i]]=1; for(int i=1; i<=n; i++) for(int j=1; j<=tot; j++) for(int t=mark[j]; t<=k; t++) for(int o=0; o<sec[j].size(); o++) { dp[i][j][t]+=dp[i-1][sec[j][o]][t-mark[j]]; } int sum=0; for(int i=1; i<=tot; i++) sum+=dp[n][i][k]; printf("%lld",sum); return 0; }