bzoj 5299: [Cqoi2018]解锁屏幕 状压dp+二进制
比较简单的状压 dp,令 $f[S][i]$ 表示已经经过的点集为 $S$,且最后一个访问的位置为 $i$ 的方案数.
然后随便转移一下就可以了,可以用 $lowbit$ 来优化一下枚举.
code:
#include <bits/stdc++.h> #define N 21 #define LL long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; const LL mod=100000007; const double eps=1e-4,inf=100000000.0; int tmp[N],v[N][N],vis[N],Log[1<<N]; LL f[1<<N][N]; int lowbit(int t) { return t&(-t); } struct data { double x,y; data(double x=0,double y=0):x(x),y(y){} }a[N]; double slope(int x,int y) { if(abs(a[x].x-a[y].x)<=eps) return inf; else return (a[x].y-a[y].y)/(a[x].x-a[y].x); } int main() { // setIO("input"); int i,j,n,k; scanf("%d",&n); Log[1]=0; for(i=2;i<(1<<N);++i) Log[i]=Log[i>>1]+1; for(i=0;i<=n;++i) tmp[i]=1<<i; for(i=0;i<n;++i) scanf("%lf%lf",&a[i].x,&a[i].y); for(i=0;i<n;++i) f[tmp[i]][i]=1ll; for(i=0;i<n;++i) { for(j=0;j<n;++j) { for(k=0;k<n;++k) { if(k!=i&&k!=j) { double slope1=slope(k,i),slope2=slope(k,j); if(abs(slope1-slope2)<=eps&&a[k].x>=min(a[i].x,a[j].x)&&a[k].x<=max(a[i].x,a[j].x)&&a[k].y>=min(a[i].y,a[j].y)&&a[k].y<=max(a[i].y,a[j].y)) { v[i][j]|=tmp[k]; } } } } } int S; LL ans=0ll; for(S=0;S<(1<<n);++S) { for(k=0;k<n;++k) { int ss=S; while(ss) { j=Log[lowbit(ss)]; if(!(S&(tmp[k]))&&(v[j][k]&S)==v[j][k]) (f[S|tmp[k]][k]+=f[S][j])%=mod; ss-=lowbit(ss); } } } for(S=0;S<(1<<n);++S) { int sz=0; for(j=0;j<n;++j) if(S&tmp[j]) ++sz; if(sz>=4) { for(j=0;j<n;++j) if(S&tmp[j]) (ans+=f[S][j])%=mod; } } printf("%lld\n",ans); return 0; }