zoukankan      html  css  js  c++  java
  • 二分答案三连发

    LA3971 Assemble

    你有b块钱,给出n个配件的个子的种类,性能和价格,每种类型的配件买一个,价格不超过b,因为有水桶效应,所以电脑的性能取决于性能最低的配件的性能,问你b块钱配的电脑性能最高有多少。

    按照白书的说法,最大值尽量小,最小值尽量大之类的问题一般都可以用二分答案的方法来结局,这道题就是一道典型的最小值最大问题,所以采用二分答案

    #include <cstdio>
    #include <cstring>
    #include <climits>
    #include <algorithm>
    #include <map>
    #include <vector>
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    const int maxn = 1005;
    
    struct Component {
    	int price,quality;
    };
    
    
    int cnt,budget,maxquality;
    map<string,int> id;
    vector<Component> comp[maxn];
    
    void readin() {
    	char name[30],power[30];
    	int p,q,n;
    	cnt = maxquality = 0;
    	scanf("%d%d
    ",&n,&budget);
    	id.clear();
    	for(int i = 0;comp[i].size();i++) {
    		comp[i].clear();
    	}
    	for(int i = 0;i < n;i++) {
    		scanf("%s%s%d%d",name,power,&p,&q);
    		int nowid;
    		if(id.count(name)) {
    			nowid = id[name];
    		} else {
    			nowid = cnt++;
    			id[name] = nowid;
    		}
    		comp[nowid].push_back((Component){p,q});
    		if(q > maxquality) {
    			maxquality = q;
    		}
    	}
    }
    
    bool ok(int val) {
    	int total = 0;
    	for(int i = 0;i < cnt;i++){
    		int cheapest = INT_MAX,m = comp[i].size();
    		for(int j = 0;j < m;j++) if(comp[i][j].quality >= val) {
    			cheapest = min(cheapest,comp[i][j].price);
    		}
    		if(cheapest == INT_MAX) return false;
    		total += cheapest;
    		if(total > budget) {
    			return false;
    		}
    	}
    	return true;
    }
    
    void work() {
    	int str = 0,end = maxquality,mid;
    	while(str < end) {
    		mid = str + (end - str + 1) / 2;
    		if(ok(mid)) {
    			str = mid;
    		} else {
    			end = mid - 1;
    		}
    	}
    	cout << str << endl;
    }
    
    int main() {
    	int T; cin >> T;
    	while(T--) {
    		readin();
    		work();
    	}
    	return 0;
    }

     

    LA3635

    你请来了F个朋友,一起来分N个圆形的派,每个人得到的必须是一块或者是一块派的一部分,而不是几块派拼在一起的,问你每个人最多能得到多大的派

    对浮点数的二分,设一个eps,当end-str<eps的时候跳出循环

    PS.常量π的值可以用const int PI = acos(-1.0)来得,这样精度比较靠谱

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    const int maxn = 10005;
    const double PI = acos(-1.0);
    const double eps = 1e-5;
    int R[maxn];
    
    inline double square(int R) {
    	return PI * R * R;
    }
    
    int main() {
    	int T,N,F;
    	scanf("%d",&T);
    	while(T--) {
    		scanf("%d%d",&N,&F);
    		int maxR = 0;
    		for(int i = 0;i < N;i++) {
    			scanf("%d",&R[i]); 
    			if(R[i] > maxR) {
    				maxR = R[i];
    			}
    		}
    		double str = 0,end = square(maxR);
    		while(end - str > eps) {
    			double mid = (str + end) / 2;
    			int count = 0;
    			for(int i = 0;i < N;i++) {
    				count += (int)(square(R[i]) / mid);
    				if(count >= F + 1) {
    					break;
    				}
    			}
    			if(count >= F + 1) {
    				str = mid;
    			} else {
    				end = mid;
    			}
    		}
    		printf("%.4lf
    ",str);
    	}
    	return 0;
    }

     

    LA 3177 Beijing Guards

    有n个人围城一个圈,每个人想拿ri种物品,要求相邻的两个人不能拿一样的,问最少需要多少种物品

    当n为偶数的时候非常好处理,只要找到最大的ri+ri-1的和就行了。

    当n为奇数的时候可以对所需要的物品数进行二分。

    第一个人需要r1件物品,设left[i],right[i]分别为第i个人从1~ri,ri+1~p中拿的物品数目,偶数的人尽量拿前面的,奇数的人尽量拿后面的,那么第n个人必定是尽量拿后面的,此时判断时候和r1冲突即可

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 100001;
    
    int r[maxn],n,sum,left[maxn],right[maxn];
    
    bool ok(int val) {
    	right[0] = 0; left[0] = r[0];
    	for(int i = 1;i < n;i++) {
    		if(r[i] > val - left[i - 1] - right[i - 1]) return false;
    		if((i + 1) % 2 == 0) {
    			left[i] = min(r[i],r[0] - left[i - 1]);
    			right[i] = r[i] - left[i];
    		} else {
    			right[i] = min(r[i],val - r[0] - right[i - 1]);
    			left[i] = r[i] - right[i];
    		}
    	}
    	return left[n - 1] == 0;
    }
    
    int bsearch() {
    	int L = 1,R = sum;
    	while(L < R) {
    		int mid = (L + R) / 2;
    		if(ok(mid)) R = mid;
    		else L = mid + 1;
    	}
    	return L;
    }
    
    int main() {
    	while(scanf("%d",&n),n) {
    		sum = 0;
    		for(int i = 0;i < n;i++) {
    		   	scanf("%d",&r[i]);
    			sum += r[i];
    		}
    		if(n % 2 == 1) printf("%d
    ",bsearch());
    		else {
    			int maxd = 0;
    			for(int i = 0;i < n;i++) {
    				int f = ((i == 0) ? n - 1 : i - 1);
    				maxd = max(maxd,r[i] + r[f]);
    			}
    			printf("%d
    ",maxd);
    		}
    	}
    	return 0;
    }

    关于二分查找的一些总结:

    很多问题都可以用二分来解决,但是根据每次寻找的条件不同,迭代的时候值的变化也会不同,简单总结一下;

    1、查找某个元素是否存在

    mid = (begin + end) / 2

    if(mid < v) begin = mid + 1;

    if(mid > v) end = mid – 1;

    if(mid == v) return v;

    2、查找不小于v的最小值

    mid = (end + begin) / 2

    if(mid < v) begin = mid + 1; else end = mid;

    3、查找大于v的最小值

    mid = (end + begin) / 2

    if(mid <= v) begin = mid + 1; else end = mid;

    3、查找满足条件的v的最小值

    mid = (begin + end) / 2

    if(ok(mid)) end = mid; else begin = mid – 1;

    4、查找满足条件的v的最大值

    mid = begin + (end – begin +1) / 2

    if(ok(mid)) begin = mid; else end = mid – 1;

    可以发现在寻找满足条件的v的最大值的时候mid取值和其他时候不一样,因为在处理两个相邻的数字的时候优先尝试大的那个,mid这样取可以保证一定比begin大,不然有可能会进入死循环

    这里顺便总结一下STL中lower_bound和upper_bound 的用法

    原型如下

    template <class ForwardIterator, class T>
      ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,const T& val);	
    template <class ForwardIterator, class T, class Compare>
      ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,const T& val, Compare comp);
    template <class ForwardIterator, class T>
      ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last,const T& val);	
    template <class ForwardIterator, class T, class Compare>
      ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last,const T& val, Compare comp);

    函数有两种重载,区别就是多了一个最后的比较函数,默认使用类的operator<,也可以自定义cmp函数,函数接受两个迭代器,分别表示一段范围,注意last表示的是最后一个元素的后一个,返回一个指向所需元素的迭代器,失败了返回last

  • 相关阅读:
    419. Battleships in a Board
    150. Evaluate Reverse Polish Notation
    153. Find Minimum in Rotated Sorted Array
    319. Bulb Switcher
    223. Rectangle Area
    iOS 常用到的宏#define
    VRAR 使用 SceneKit
    VR、AR、MR定义区别
    Swift 开源项目练习应用
    Swift3.0 UITextField
  • 原文地址:https://www.cnblogs.com/rolight/p/3541426.html
Copyright © 2011-2022 走看看