1. 程式人生 > >2018.11.06【SCOI2005】【BZOJ1087】【洛谷P1896】互不侵犯(狀壓DP)

2018.11.06【SCOI2005】【BZOJ1087】【洛谷P1896】互不侵犯(狀壓DP)

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; }