解锁锁.
状压DP呀,预处理两个点链接需要的必经点,然后DP就好惹
BZOJ 5299
Luogu 4460
速度差距巨大…
DP版:
#include
#include
#include
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<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
#include
#include
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 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;
}