@ysner
2018-05-12T10:54:23.000000Z
字数 1522
阅读 1833
状压DP
这数据范围显然是状压。
可以发现,区分不同方案的标准是选的点和终结点。
于是设表示当选点状态为,最后选的点为时的方案数。
然后预处理一下连两点时中间经过的其它点(这里注意判断条件问题,不能少等于号)。
再通过储存、延伸状态,统计时枚举下一个点,枚举中间点判是否路过未经过的点即可。
目测复杂度
但是我发现我傻逼了,好像就可以判不合法呢。
于是复杂度降到。
然后因用被卡爆,被迫改成暴枚状态。。。
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define mp make_pair
#define ll long long
#define re register
#define il inline
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define fp(i,a,b) for(re int i=a;i<=b-1;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=1<<20,mod=1e8+7;
int n,way[30][30],x[30],y[30],dp[30][N],now,s;
ll ans;
il int gi()
{
re int x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
int main()
{
n=gi();
fp(i,0,n) x[i]=gi(),y[i]=gi();
fp(i,0,n)
fp(j,0,n)
fp(k,0,n)
if(k!=i&&k!=j&&x[k]>=min(x[i],x[j])&&x[k]<=max(x[i],x[j])&&y[k]>=min(y[i],y[j])&&y[k]<=max(y[i],y[j]))
if((y[k]-y[i])*(x[j]-x[i])==(y[j]-y[i])*(x[k]-x[i])) way[i][j]|=(1<<k);
fp(i,0,n) dp[i][1<<i]=1;
fp(now,0,(1<<n))
fp(s,0,n)
{
if(!(now&(1<<s))||!dp[s][now]) continue;
fp(i,0,n)
{
if((1<<i)&now) continue;
if((way[s][i]&now)!=way[s][i]) continue;
dp[i][now|(1<<i)]+=dp[s][now];
if(dp[i][now|(1<<i)]>=mod) dp[i][now|(1<<i)]-=mod;
}
}
fp(now,0,(1<<n))
{
re int tot=0,ysn=now;
for(;ysn;ysn-=ysn&-ysn) ++tot;
if(tot>3)
fp(i,0,n) if((1<<i)&now)
{
ans+=dp[i][now];
if(ans>=mod) ans-=mod;
}
}
printf("%lld\n",ans);
return 0;
}