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

    题目

    传送门

    思路

    个人感觉我的思路并不是很优

    m貌似没什么用(可能是部分分),直接忽略

    但是看到n最大才去到18,不是状压就是爆搜,我采用的是DFS维护状压DP的转移(其实有点像记忆化搜索)

    注意:为了方便状压,以下小猪的编号从0~n-1

    设状态k二进制下第i为表示:第i只小猪的消灭情况0:没消灭,1:消灭,f[k]表示状态为k时最少用的小鸟数量

    状态转移:

    [f_k=min(f_{s}+1) ]

    其中s满足(s | k == k)且对于所有i,i满足((k >> i)&1==1 ,(s>>i)&1==0),编号为i的小猪在同一条合法的抛物线上(即可以用同一只小鸟解决)

    特别地,当k的二进制下只有一位为"1"时,f[k]=1,k==0时,f[k]=0.

    所以对于每个状态k,我们需要枚举两只小猪i,j,再去掉和小猪i,j在同一条合法抛物线上的小猪,时间复杂度O(n3×2n)是会超时的

    优化:

    1. 预处理小猪两两组合产生的抛物线:常数级优化

    2. 考虑到在同一条抛物线上的小猪两两组合产生的抛物线是一样的,不必重复枚举,所有对于每一次dfs转移,定义vis[i] [j]表示是有枚举过小猪i,j,若找到小猪k,k与i,j在同一条抛物线上

     vis[i][k] = vis[k][i] = vis[j][k] = vis[k][j] = true
    

    ​ 玄学级优化

    1. 题解上有说预处理所有和i,j在同一条抛物线上的小猪,但是我没写出来,题解传送门,优化为O(n2×2n)

    然后发现还是有两个TLE我一气之下开了O2把这题切了

    一些小问题

    精度:

    亲测1e-4是不够的,最后我开的是1e-8

    抛物线解析式:

    具体查看初二的数学课本,不做赘述

    inline void cal(int i , int j , double &a , double &b) {
    	if(x[i] == 0 || x[j] == 0 || x[i] == x[j]) {
    		a = 999;//不合法
    		return;
    	}
    	a = (y[i] * x[j] - y[j] * x[i])/(x[i] * x[j] * (x[i] - x[j]));
    	b = y[i] / x[i] - a * x[i];
    }
    

    tips:

    测试数据

    代码

    我的(1.cpp)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define rr register
    //#pragma GCC optimize(2)
    using namespace std;
    int read() {
    	int re = 0 , sig = 1;
    	char c = getchar();
    	while(c < '0' || c > '9'){
    		if(c == '-')sig = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9'){
    		re = (re << 1) + (re << 3) + c - '0';
    		c = getchar();
    	}
    	return re * sig;
    }
    int n;
    double x[20] , y[20];
    double aa[20][20] , bb[20][20];
    inline void cal(int i , int j , double &a , double &b) {
    	if(x[i] == 0 || x[j] == 0 || x[i] == x[j]) {
    		a = 9;
    		return;
    	}
    	a = (y[i] * x[j] - y[j] * x[i])/(x[i] * x[j] * (x[i] - x[j]));
    	b = y[i] / x[i] - a * x[i];
    }
    inline double fabss(double a) {
    	return a < 0  ? -a : a;
    }
    inline bool check(double a , double b , int i) {
    	return fabss(a * x[i] * x[i] + b * x[i] - y[i]) < 1e-8;
    }
    inline int count_(int x){
    	int cnt = 0;
    	while(x != 0){
    		x = x & (x - 1);
    		cnt++;
    	}
    	return cnt;
    }
    void print(int x) {
    	if(x >= 2)
    		print(x / 2);
    	putchar(x % 2 + 48);
    }
    int f[1 << 20];
    int dfs(rr int stat) {
    	if(f[stat] != -1)
    		return f[stat];
    	double a , b;
    	int count_res = count_(stat);
    	if(count_res == 0)
    		return 0;
    	if(count_res == 1)
    		return 1;
    	if(count_res == 2){
    		int i = 0 , j = 0 , tmp = stat;
    		while(1) {
    			if(tmp & 1)
    				break;
    			tmp >>= 1 , ++i , ++j;
    		}
    		tmp >>= 1;
    		++j;
    		while(1) {
    			if(tmp & 1)
    				break;
    			tmp >>= 1 , ++j;
    		}
    		a = aa[i][j];
    		b = bb[i][j];
    //		cout << i << '	' << j << endl;
    		f[stat] = (a >= 0 ? 2 : 1);
    		return f[stat];
    	}
    	
    	bool vis[20][20];
    	memset(vis , 0 , sizeof(vis));
    	
    	f[stat] = count_res;
    	rr int tmp , temp;
    	for(rr int i = 0 ; i < n ; ++i)
    		if((stat >> i) & 1)
    			for(rr int j = 0 ; j < n ; ++j) {
    				if(vis[i][j])continue;
    				vis[i][j] = vis[j][i] = true;
    				
    				if(((stat >> j) & 1) == 0)	continue;
    				if(i == j)continue;
    				a = aa[i][j];
    				b = bb[i][j];
    				if(a >= 0)continue;
    				tmp = stat;
    				tmp ^= (1 << i);
    				tmp ^= (1 << j);
    				for(rr int k = 0 ; k < n ; ++k)
    					if(((tmp >> k) & 1 ) == 1 && check(a , b , k)) {
    						tmp ^= (1 << k);
    						vis[i][k] = vis[k][i] = vis[j][k] = vis[k][j] = true;
    					}
    				
    				temp = (f[tmp] == -1 ? dfs(tmp) + 1 : f[tmp] + 1);
    				if(temp < f[stat]) {
    					f[stat] = temp;
    				}
    			}
    	return f[stat];
    }
    int main() {
    //	freopen("angrybirds13.in" , "r" , stdin);
    	int T = read();
    	while(T--) {
    		memset(f , -1 , sizeof(f));
    		n = read();
    		read();
    		for(int i = 0 ; i < n ; i++)
    			cin >> x[i] >> y[i];
    		for(int i = 0 ; i < n ; ++i)
    			for(int j = 0 ; j < n ; ++j)
    				if(i != j)
    					cal(i , j , aa[i][j] , bb[i][j]);
    		cout << dfs((1 << (n)) - 1) << endl;
    	}
    	return 0;
    }
    

    自测程序(compare.cpp)

    请将下载的数据,待测程序,自测程序放在同一文件夹下

    #include <bits/stdc++.h>
    using namespace std;
    string itos(int x) {
    	string s;
    	while(x != 0){
    		s = (char)(x % 10 + 48) + s;
    		x /= 10;
    	}
    	return s;
    }
    int main() {
    	for(int i = 1 ; i <= 20 ; i++) {
    		printf("No.%d
    " , i);
    		int t = clock();
    		system(("1.exe < " + (string)"angrybirds" + itos(i) + ".in " + " > output.txt").c_str());
    		printf("%dms
    " , clock() - t);
    		if(system(("fc output.txt " + (string)"angrybirds" + itos(i) + ".ans").c_str())){
    			cout << "WA!
    ";
    			system("pause");
    		}//*/
    	}
    	return 0;
    }
    
  • 相关阅读:
    行业基本面量化之商业银行
    [茶思]另类数据及其在投资中的应用
    [茶思]机器学习与宏观基本面方法在债券定价中的应用
    [宏观追踪]美国2020年2月
    [饭想]可转债市场的发展趋势
    [读论文]谷歌搜索量与个人投资者交易行为
    [读论文]基金评级及其激励
    [读论文]懒价格
    [宏观追踪]中国2020年2月
    虚拟机nat-网络认知-更正(vmware 的nat规则设置完网关,虚拟机设置自己网络就完事了。物理机相当于双网卡 物理和vmware8,8只是为了物理机xshell连接虚拟机,禁用了虚拟机照样上网)
  • 原文地址:https://www.cnblogs.com/dream1024/p/13957910.html
Copyright © 2011-2022 走看看