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

    题目链接

    problem

    平面内有n个点,每次可以确定一条过原点且开口向上的抛物线,将这条抛物线上所有的点都删去。问最少需要删几次可以删掉全部的点。

    solution

    n比较小,直接状压一下。因为已经确定了要过原点。所以每两个点都可以确定一条抛物线。预处理出所有抛物线以及每条抛物线可以删掉的点。

    然后记忆化搜索,枚举每次选择的抛物线。转移即可。

    注意精度!

    确定抛物线的方法就用解二元一次方程组的方法即可。具体如下:

    设抛物线的二次项系数为(a),一次项系数为(b) ,两个点的坐标分别为((x_i,y_i),(x_j,y_j))

    (k_1=x_i^2,k_2=x_i,k_3=y_i,k_4=x_j^2,k_5=x_j,k_6=y_j)

    然后就是解方程组

    [left{ egin{aligned} k_1a+k_2b=k_3& &(1)\ k_4a+k_5b=k_6& &(2) end{aligned} ight. ]

    ((1))(b=frac{k_3-k_1a}{k_2}),代回((2))(a=frac{k_2k_6-k_3k_5}{k_2k_4-k_1k_5})

    code

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<ctime>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const double eps = 1e-9;
    ll read() {
    	ll x = 0,f = 1;char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		x = x * 10 + c - '0';
    		c = getchar();
    	}
    	return x * f;
    }
    int tot;
    bool calc(double a,double b,double x,double y) {
    	return fabs(a * x * x + b * x - y) <= eps;
    }
    double x[20],y[20],a[400],b[400];
    int sol[400];
    int n,m,f[1 << 20];
    int dfs(int now) {
    	if(!now) return f[now] = 0;
    	if(f[now] != -1) return f[now];
    	int ret = 100000;
    	for(int i = 1;i <= tot;++i) {
    		int t = now & sol[i];
    		if(t != now) ret = min(ret,dfs(t) + 1);
    	}
    	return f[now] = ret;
    }
    int main() {
    	int T = read();
    	while(T--) {
    		tot = 0;
    		memset(f,-1,sizeof(f));
    		n = read(),m = read();
    		for(int i = 1;i <= n;++i) scanf("%lf%lf",&x[i],&y[i]);
    		
    		for(int i = 1;i <= n;++i) {
    			for(int j = i + 1;j <= n;++j) {
    				if(fabs(x[i] - x[j]) <= eps) continue;
    				++tot;
    				double k1 = x[i] * x[i],k2 = x[i],k3 = y[i],k4 = x[j] * x[j],k5 = x[j],k6 = y[j];
    				a[tot] = ((k6 * k2 - k3 * k5)) / ((k4 * k2 - k1 * k5));
    				b[tot] = (k3 - k1 * a[tot]) / k2;
    				if(a[tot] >= 0) --tot;
    			}
    		}
    		
    		
    		for(int i = 1;i <= tot;++i) {
    			
    			sol[i] = (1 << n) - 1;
    			
    			for(int j = 1;j <= n;++j) 
    				if(calc(a[i],b[i],x[j],y[j])) sol[i] ^= (1 << (j - 1));	
    		}
    		
    		for(int i = 1;i <= n;++i) {
    			++tot;
    			sol[tot] = ((1 << n) - 1) ^ (1 << (i - 1));
    		}
    		
    		printf("%d
    ",dfs((1 << n) - 1));
    	}
    	
    	return 0;
    }
    
    
  • 相关阅读:
    [转]How can I create a design netlist without including my source design files?
    [转]基于FPGA的以太网开发
    [转]GMII/RGMII/SGMII/TBI/RTBI接口信号及时序介绍
    [原]Altium画PCB时鼠标十字不能对准焊盘中心
    [转]Altera特殊管脚的使用(适用全系列Altera FPGA,MSEL区别除外)-来自altera论坛
    [转]STM32正交编码器驱动电机
    [转]使用D触发器制作正交编码器的鉴相电路
    [转]解决STM32开启定时器时立即进入一次中断程序问题
    [转]ISE iMPACT bit生成mcs
    [转]NiosII处理器软件代码优化方法
  • 原文地址:https://www.cnblogs.com/wxyww/p/11628340.html
Copyright © 2011-2022 走看看