Brush (IV) LightOJ - 1018
2018-06-17 21:40:45来源:未知 阅读 ()
题意:平面上有一些点,每刷一次可以把同一条直线上的点都刷光,问最少几次把所有点刷光。
方法:
显然是一个状态压缩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.复杂度错误,$O(T*n^3*2^n)$
2.被卡常,用http://blog.csdn.net/kijamesqi/article/details/50533691的方法卡过去
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 }
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
下一篇:c++学习笔记
- P1018 乘积最大(DP) 2019-08-16
- 2018-10-06 Gym-101864F丨STL爽题丨想法 2018-10-08
- Easy Game LightOJ - 1031 2018-06-27
- N Queen Again LightOJ - 1061 2018-06-27
- PAT/简单模拟习题集(二) 2018-06-18
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash