zoukankan      html  css  js  c++  java
  • NOIP2016 愤怒的小鸟

    这道题看到数据范围,我们就知道:小于等于18,一定使用状态压缩,即O(2^n*一个东西),在算一下,我们发现,像NOIP这种考试,一定会考卡常数的题,所以瞬间得出这道题的算法是O(2^n*n^2*cases).

    显然这道题我们可以当做直线来做:y=a*x^2+b*x可以合并同类项得y=x*(a*x+b),那么,我们就把y/x当做y,即y=k*x+b.

    #include<cstdio>

    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    const int inf=0x3f3f3f3f;
    const long double eps=1e-9;//它应该会有一些精度误差,所以我们要避免这种情况
    long double x[25],y[25];
    int f[(int)(1<<18+5)],g[22][22];
    int multi[25];
    long double k,b;
    int n,m,cases;
    int s;
    int main(){
        scanf("%d",&cases);
        for(int i=1;i<=22;i++){
         multi[i]=1<<(i-1);//预处理,避免多余的计算,即卡常数
    }
        while(cases--){
         memset(f,inf,sizeof(f));
         memset(g,0,sizeof(g));
         f[0]=0;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++){
             scanf("%llf%llf",&x[i],&y[i]);
             y[i]/=x[i];//把它转化为一条直线

            }

    //这里,我们要用到两者确定一条直线的思想,先以第i个点和第j个点为一条直线,在看有没有其他点在这条直线上

            for(int i=1;i<=n;i++){
                g[i][i]=multi[i];
                for(int j=i+1;j<=n;j++){
                    if(x[i]==x[j]){//如果两者的x坐标相同,那么就忽略
                       continue;
                    }
                    k=(y[j]-y[i])/(x[j]-x[i]);
                    b=y[j]-x[j]*k;//算出这条直线的k和b

                    if(k<0){//如题目说了,只有k是负数,我们才能算作一条直线
                       g[i][j]=(multi[i])+(multi[j]);//位运算
                       for(int l=1;l<=n;l++){
                           if(abs(y[l]-(k*x[l]+b))<eps){
                              g[i][j]=g[i][j]|(multi[l]);//把这个点加入直线,如果是i或j,为不会影响
                           } 
                       }
                    }

                }
            }
            s=1<<n;
            for(int i=1;i<s;i++){
                for(int j=1;j<=n;j++){
                    for(int l=j;l<=n;l++){
                        if(i&g[j][l]==0)continue;//如果这状态没有包括一个在这条直线上的点,就算了(反正也是浪费)
                        else{
                            f[i]=min(f[i],f[((i|g[j][l])-g[j][l])]+1);//把这条直线上点全部去点以后在加上这条直线
                        }

                    }
                }
            }
            printf("%d ",f[s-1]);
        }
        return 0;
    }
  • 相关阅读:
    HDU 6197 array array array nlogn求最长子序列 思维
    HDU 6198 number number number 矩阵快速幂 找规律
    HDU 6195 cable cable cable 思维
    urumuqi 网络赛 H skiing DP
    urumqi 网络赛 E Half-consecutive Numbers 数论
    urumqi 网络赛 C Coconut 水题
    UVA 122 Trees on the level 二叉树 广搜
    POJ3468【线段树lazy操作】
    线段树萌新讲解+一道水题【一点一滴】
    hdoj5792 【树状数组】【未完待续】
  • 原文地址:https://www.cnblogs.com/c201904xyorz/p/9990788.html
Copyright © 2011-2022 走看看