[CQOI2018] 解锁屏幕

91 篇文章 1 订阅
16 篇文章 0 订阅

题目描述:

解锁锁.

题目分析:

状压DP呀,预处理两个点链接需要的必经点,然后DP就好惹

题目链接:

BZOJ 5299
Luogu 4460

Ac 代码:

速度差距巨大…
DP版:

#include <cstdio>
#include <iostream>
#include <queue>
const int mod=100000007,maxm=21;
int ans=0;
int n;
int f[maxm][1<<20],a[maxm][maxm],x[maxm],y[maxm];
bool vis[maxm][1<<20];
inline bool atline(int d,int a,int b)
{
    if(x[d]<std::min(x[a],x[b])||x[d]>std::max(x[a],x[b])||y[d]<std::min(y[a],y[b])||y[d]>std::max(y[a],y[b])) return 0;
    return ((x[d]-x[a])*(y[b]-y[d])-(x[b]-x[d])*(y[d]-y[a])==0);
}
inline bool check(int sta)
{
    int cnt=0;
    for(int i=1;i<=n;i++) if((1<<(i-1))&sta) cnt++;
    return cnt>=4;
}
inline void add(int &a,int b)
{
    a+=b;
    if(a>=mod) a%=mod;
}
inline int read()
{
    int a=0,w=1;
    char ch=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
     a=(a<<3)+(a<<1)+ch-'0',ch=getchar();
    return a*w;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
     x[i]=read(),y[i]=read();
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
      if(i!=j)
       for(int k=1;k<=n;k++)
        if(j!=k&&i!=k)
         if(atline(k,i,j)) a[i][j]|=(1<<(k-1));
    for(int i=1;i<=n;i++) f[i][1<<(i-1)]=1;
    for(int s=0;s<(1<<n);s++)
    {
        int flag=check(s);
        for(int i=1;i<=n;i++)
        if(f[i][s])
        {
            if(flag) add(ans,f[i][s]);
            for(int j=1;j<=n;j++)
             if(!(s&(1<<(j-1))))
              if((s&a[i][j])==a[i][j])
               add(f[j][s|(1<<(j-1))],f[i][s]);
        }
    }
    printf("%d\n",ans);
    return 0;
}

队列实现版:

#include <cstdio>
#include <iostream>
#include <queue>
const int mod=100000007,maxm=21;
int ans=0;
int n;
struct node{
    int last,sta,cnt;
};
int f[maxm][1<<20],a[maxm][maxm],x[maxm],y[maxm];
bool vis[maxm][1<<20];
std::queue <node> dl;
inline bool atline(int d,int a,int b)
{
    if(x[d]<std::min(x[a],x[b])||x[d]>std::max(x[a],x[b])||y[d]<std::min(y[a],y[b])||y[d]>std::max(y[a],y[b])) return 0;
    return ((x[d]-x[a])*(y[b]-y[d])-(x[b]-x[d])*(y[d]-y[a])==0);
}
inline void add(int &a,int b)
{
    a+=b;
    if(a>=mod) a%=mod;
}
inline int read()
{
    int a=0,w=1;
    char ch=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
     a=(a<<3)+(a<<1)+ch-'0',ch=getchar();
    return a*w;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
     x[i]=read(),y[i]=read();
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
      if(i!=j)
       for(int k=1;k<=n;k++)
        if(j!=k&&i!=k)
         if(atline(k,i,j)) a[i][j]|=(1<<(k-1));
    for(int i=1;i<=n;i++) f[i][1<<(i-1)]=1,dl.push((node){i,1<<(i-1),1}),vis[i][1<<(i-1)]=1;
    while(!dl.empty())
    {
        node now=dl.front();
        dl.pop();
        if(now.cnt>=4) add(ans,f[now.last][now.sta]);
        for(int i=1;i<=n;i++)
        if(!((1<<(i-1))&now.sta))
        {
            if((now.sta&a[now.last][i])!=a[now.last][i]) continue;
            add(f[i][now.sta|(1<<(i-1))],f[now.last][now.sta]);
            if(!vis[i][now.sta|(1<<(i-1))]) dl.push((node){i,now.sta|(1<<(i-1)),now.cnt+1}),vis[i][now.sta|(1<<(i-1))]=1;;
        }
    }
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值