CQOI2018 解锁屏幕

题目链接:戳我

其实只有开了O2才能A.......

就是我们看到n的范围这么小,就想到状压DP。然后我们设状态dp[i]表示状态为i的(二进制表示该点选或者不选),方案数有多少个。

但是我们发现因为还要枚举转移下一个点,所以我们还要记录一下最后的那个点是什么。

于是我们修改状态为\(dp[i][j]\)表示当前状态为i,最后一个点的编号为j的,方案数有多少个。

然后\(O(2^n*n^2)\).......吧

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define MAXN 21
#define eps 1e-7
#define mod 100000007
using namespace std;
int n,m,ans;
int dp[1<<MAXN][MAXN];
struct Node{int x,y;}node[MAXN];
vector<int>mid[MAXN][MAXN];
inline bool cmp(struct Node a,struct Node b)
{
    if(a.x==b.x) return a.y<b.y;
    return a.x<b.x;
}
inline bool check(int a,int b,int c)
{
    double k1,k2;
    if(node[a].x==node[b].x&&node[a].x==node[c].x) return true;
    else if(node[a].x==node[c].x||node[a].x==node[b].x) return false;
    k1=1.0*(node[a].y-node[b].y)/(node[a].x-node[b].x);
    k2=1.0*(node[a].y-node[c].y)/(node[a].x-node[c].x);
    if(fabs(k1-k2)<eps) return true;
    else return false;
}
inline bool more_than_4(int x)
{
    int cur_ans=0;
    for(int i=0;i<n;i++)
        if(x&(1<<i))
            cur_ans++;
    return cur_ans>=4;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
            scanf("%d%d",&node[i].x,&node[i].y);
    sort(&node[1],&node[n+1],cmp);
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            for(int k=i+1;k<=j-1;k++)
                if(check(i,j,k)==true)
                    mid[i][j].push_back(k);
    for(int i=1;i<=n;i++) dp[1<<(i-1)][i]=1;
    for(int i=1;i<(1<<n);i++)
    {
        for(int j=1;j<=n;j++)
        {
            if((i>>(j-1))&1) continue;
            int s=(i|(1<<(j-1)));
            for(int k=1;k<=n;k++)
            {
                if(k==j) continue;
                int x=min(j,k),y=max(j,k),flag=0;
                for(int t=0;t<mid[x][y].size();t++)
                    if(!((i>>(mid[x][y][t]-1))&1)){flag=1;break;}
                if(flag==1) continue;
                dp[s][j]=(dp[s][j]+dp[i][k])%mod;
            }
        }
    }
    for(int i=1;i<(1<<n);i++)	
        if(more_than_4(i))
            for(int j=1;j<=n;j++)
                ans=(ans+dp[i][j])%mod;
    printf("%d\n",ans);
    return 0;
}

posted @ 2019-05-22 23:20  风浔凌  阅读(128)  评论(0编辑  收藏  举报