洛谷传送门node
使用过Android 手机的同窗必定对手势解锁屏幕不陌生。Android 的解锁屏幕由3X3 个点组成,手指在屏幕上画一条线,将其中一些点链接起来,便可构成一个解锁图案。以下面三个例子所示:spa
画线时还须要遵循一些规则:code
对于最后一条规则,参见下图的解释。左边两幅图违反了该规则; 而右边两幅图(分别为2->4-1-3-6 和6->5-4->1->9-2) 则没有违反规则,由于在“跨过”点时,点已经被“使用”过了。对象
如今工程师但愿改进解锁屏幕,增减点的数目,并移动点的位置,再也不是一个九宫格形状,但保持上述画线的规则不变。请计算新的解锁屏幕上,一共有多少知足规则的画线方案。blog
输入文件第一行,为一个整数n,表示点的数目。get
接下来n 行,每行两个空格分开的整数x_i*x**i* 和y_i*y**i*,表示每一个点的坐标。it
输出文件共一行,为题目所求方案数除以100000007 的余数。io
输入 #1复制class
输出 #1复制搜索
输入 #2复制
输出 #2复制
样例#1解释: 设4 个点编号为1到4,方案有1->2->3->4,2->1->3->4,3->2->1->4,2->3->1->4,及其镜像4->3->2->1,3->4->2->1,2->3->4->1,3->2->4->1。
对于30%的数据,1≤n≤101≤n≤10
对于100%的数据,-1000≤x_i,y_i≤1000,1≤n<20−1000≤xi,yi≤1000,1≤n<20。各点坐标不相同
七哥@littleseven 推荐的题。必需要作
看到方案数想到递推,而后\(1\le N\le 20\)。因此想到状态压缩。而后七哥让我推状态。我一想,若是开多维的话可能空间会爆,因此考虑只开一维,压成一个\(1<<n\)的状态,表示每一个点是否被链接。
后来发现无法转移。因此考虑再开一维,因而处处搜索...拿什么作第二维能保证既能转移又不会挂空间呢?
一看数据范围,只有点数的二十还符合第二点要求,因此就选择这个作状态。苦思冥想看完题解以后,以为把状态设置成这样最合适:
\(dp[i][j]\)表示点的选择情况为\(i\)、选择的点集中终点为\(j\)时的方案数。
那么,针对于一个已定的状态\(i\),它能转移的对象是这个状态中不为1的点。
举例:
\(dp[10010][2]\)能够转移到\(dp[11010][4],dp[10011][1]\)等状态。咱们在转移的时候判一下这个点可不能够转移便可。(条件是转移前的\(j\)和转移后的\(j\)连上的直线上全部的点所有已经被到达过)
这样的话,咱们能够先把两点间的点开\(vector\)存下,而后进行递推。
发现只连一个点的方案数是1.这个当初值。
咱们转移的时候记录把当前状态用\(st\)记录下来,而后再用\(k\)枚举上一层状态,若是符合条件(即上面的点都被通过了,用\(flag\)标记判断进行转移就好)
转移方程是:
\[ dp[st][j]=(dp[st][j]+dp[i][k])\quad(mod\,\,\,p) \]
完整代码就是:
#include<cstdio> #include<vector> #include<algorithm> using namespace std; const int mod=1e8+7; int n; bool flag; int dp[1<<20][21]; struct node { int x,y; }a[21]; bool cmp(node a,node b) { if(a.x==b.x) return a.y<b.y; return a.x<b.x; } vector<int> vec[21][21]; bool check(node a,node b,node c) { return (a.x-b.x)*(b.y-c.y)==(b.x-c.x)*(a.y-b.y)?1:0; } int lowbit(int x) { int ret=0; while(x) { x-=(x&(-x)); ret++; } return ret; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y); sort(a+1,a+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;k++) if(check(a[i],a[k],a[j])) vec[i][j].push_back(k); for(int i=1;i<=n;i++) dp[1<<(i-1)][i]=1; for(int i=0;i<(1<<n);i++) for(int j=1;j<=n;j++) { if((i>>(j-1))&1) continue; int st=(i|(1<<(j-1))); for(int k=1;k<=n;k++) { if(k==j) continue; int xx=min(j,k); int yy=max(j,k); flag=0; for(int t=0;t<vec[xx][yy].size();t++) if(!((i>>(vec[xx][yy][t]-1))&1)) { flag=1; break; } if(flag) continue; dp[st][j]=(dp[st][j]+dp[i][k])%mod; } } int ans=0; for(int i=0;i<(1<<n);i++) { if(lowbit(i)<4) continue; for(int j=1;j<=n;j++) ans=(ans+dp[i][j])%mod; } printf("%d",ans); return 0; }