2018.11.06【SCOI2005】【BZOJ1087】【洛谷P1896】互不侵犯(狀壓DP)
阿新 • • 發佈:2018-11-10
BZOJ傳送門
洛谷傳送門
解析:
範圍只有9,顯然是狀壓DP。
考慮處理出每個可能的狀態來減小常數。
然後列舉行,列舉當前行狀態,列舉前一行狀態,更新即可。
注意要預處理第一行的情況。
程式碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=1<<10;
int sta[N],num[N],cnt;
ll f[10][N][200];
int n,k;
signed main(){
n=getint();
k=getint();
for(int re i=0;i<(1<<n);++i){
if(i&(i<< 1))continue;
sta[++cnt]=i;
int p=i;
while(p){
p-=p&-p;
++num[cnt];
}
}
for(int re i=1;i<=cnt;++i)f[1][i][num[i]]=1;
for(int re i=2;i<=n;++i){
for(int re j=1;j<=cnt;++j){
for(int re t=1;t<=cnt;++t){
if((sta[t]&sta[j])||(sta[t]&(sta[j]<<1))|| (sta[t]&(sta[j]>>1)))continue;
for(int re kkk=0;kkk<=k;++kkk)f[i][j][num[j]+kkk]+=f[i-1][t][kkk];
}
}
}
ll ans=0;
for(int re i=1;i<=cnt;++i)ans+=f[n][i][k];
cout<<ans;
return 0;
}