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

  

posted @ 2019-11-06 20:59  EM-LGH  阅读(134)  评论(0编辑  收藏  举报