zoukankan      html  css  js  c++  java
  • Brush (IV) LightOJ

    题意:平面上有一些点,每刷一次可以把同一条直线上的点都刷光,问最少几次把所有点刷光。

    方法:

    显然是一个状态压缩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
    ",TT,ans[left[n]-1]);
    65     }
    66     return 0;
    67 }
  • 相关阅读:
    Mongo 配置文件 [www]
    网络上最完整的网络克隆教程
    perl操作MongoDB
    [C#项目开源] MongoDB 可视化管理工具 (2011年10月-至今)
    maven ClassNotFoundException: org.springframework.web.context.ContextLoader
    执行update操作的话,就会报“Connection is read-only. Queries leading to data modification are not allowed”的异常。
    解压war包
    删除文件夹
    查看端口是否被占用
    springmvc 注解
  • 原文地址:https://www.cnblogs.com/hehe54321/p/loj-1018.html
Copyright © 2011-2022 走看看