Brush (IV) LightOJ - 1018
Posted 哈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Brush (IV) LightOJ - 1018相关的知识,希望对你有一定的参考价值。
题意:平面上有一些点,每刷一次可以把同一条直线上的点都刷光,问最少几次把所有点刷光。
方法:
显然是一个状态压缩dp。ans[S]表示把S集合中点刷掉的最少次数。最开始想到的方法是如果S中只有一个或两个点,那么ans[S]=1。否则枚举S中任意两点i,j作为直线上的点,并算出经过i,j的直线还过S中其他多少个点,那么ans[S]=min(ans[S],ans[S去掉那条直线经过的所有点]+1)。自然而然的就想到应该预处理出过i,j两点的直线过的其他点的集合,只需要枚举i,j和另外一个点再判是否共线即可。
这里需要用到判三点共线:https://www.zybang.com/question/ca7778a2e315afb588629121177b6772.html
A(x1,y1),B(x2,y2),C(x3,y3),则(x2-x1)×(y3-y2)=(x3-x2)×(y2-y1)
但是,这样时间复杂度是$O(T*n^3*2^n)$,还是太慢了。
观察一下可以发现:由于一个集合中所有点早晚都要刷掉,只需要指定任意一个点作为直线上的点,再枚举另一个点就行了。
那么,复杂度降低到$O(T*n^2*2^n)$。对于单组数据复杂度已经可以接受,但是由于T比较大,还是不能通过。
接下来开始卡常:
1.把循环的dp改成记忆化搜索能快许多,因为最终状态不一定需要其他所有状态的答案。
2.在开始时预处理出每个集合S的所有元素,而不是每次枚举编号判断是否在S内
3.常规(meiyong):快读,预处理左移
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int x[30],y[30]; 6 int T,TT,n,fff; 7 int ans[140000]; 8 int tmp[30][30]; 9 int left[30]; 10 int G[70000][30]; 11 void read(int&x) 12 { 13 x=0; 14 char ch=getchar();fff=1; 15 while(ch<‘0‘||ch>‘9‘) 16 { 17 if(ch==‘-‘) fff=-1; 18 ch=getchar(); 19 } 20 while(ch>=‘0‘&&ch<=‘9‘) x=(x<<1)+(x<<3)+ch-‘0‘,ch=getchar(); 21 x*=fff; 22 } 23 int main() 24 { 25 int i,j,k,t1,t2; 26 for(i=0;i<30;i++) left[i]=(1<<i); 27 for(i=1;i<70000;i++) 28 for(k=0;k<17;k++) 29 if(i&left[k]) 30 G[i][++G[i][0]]=k; 31 read(T); 32 for(TT=1;TT<=T;TT++) 33 { 34 read(n); 35 for(i=0;i<n;i++) 36 read(x[i]),read(y[i]); 37 //memset(tmp,0,sizeof(tmp)); 38 for(i=0;i<n;i++) 39 for(j=i+1;j<n;j++) 40 { 41 tmp[i][j]=0; 42 t1=x[j]-x[i]; 43 t2=y[j]-y[i]; 44 for(k=0;k<n;k++) 45 if(t1*(y[k]-y[j])==(x[k]-x[j])*t2) 46 tmp[i][j]|=left[k]; 47 tmp[j][i]=tmp[i][j]; 48 } 49 //memset(ans,0x3f,sizeof(ans)); 50 ans[0]=0; 51 for(i=1;i<left[n];i++) 52 { 53 if(__builtin_popcount(i)<=2) 54 ans[i]=1; 55 else 56 { 57 ans[i]=0x3f3f3f3f; 58 //每个点都迟早要被刷,因此枚举任意一个点作为直线上点即可,不用枚举两个 59 j=G[i][1]; 60 for(k=2;k<=G[i][0];k++) 61 ans[i]=min(ans[i],ans[i^(tmp[j][G[i][k]]&i)]+1); 62 } 63 } 64 printf("Case %d: %d\n",TT,ans[left[n]-1]); 65 } 66 return 0; 67 }
以上是关于Brush (IV) LightOJ - 1018的主要内容,如果未能解决你的问题,请参考以下文章
(状压) Brush (IV) (Light OJ 1018)