Valle bajo P6174 [USACO16JAN] Vacas enojadas S (Shang Xian)

Portal de títulos

Idea central: respuesta dicotómica

1. ¿Qué es una respuesta dicotómica?

En un intervalo monótono no decreciente o monótono no creciente, necesitamos encontrar una respuesta para que la condición del problema se mantenga. El método más simple es la enumeración, la complejidad del tiempo es O (n), y puede tratar algunos problemas con datos pequeños. También puede encontrar este valor por dicotomía. La complejidad del tiempo es O (logn), que es un algoritmo excelente en el tiempo.

2. ¿Por qué esta pregunta puede dividirse en dos respuestas?

Debido a que el valor R que estamos buscando es un número natural, por supuesto, lo estamos buscando en un intervalo creciente, que es consistente con las características de la respuesta dicotómica.

3. ¿Lugar específico?

Ordenamos la matriz original en orden ascendente para obtener el valor máximo. Siempre que piense detenidamente, puede comprender que la R que buscamos debe estar entre 00 ~ \ max (a [i]) max (a [i]).

Luego, después de ordenar l=0,r=a[n], puede verificar si mid cumple la condición cada vez.

Si se cumplen las condiciones, este valor puede ser menor, por lo que r se reduce para hacerr=mid-1

Por el contrario, significa que el número es demasiado grande, por lo tanto, reduzca l para hacerl=mid+1

¿Cómo probarlo?

La esencia de la respuesta dicotómica reside en la función de juicio.

Usamos una variable para simular el progreso actual de la explosión. Mientras el progreso de la explosión no alcance el siguiente alcance, entonces necesitamos lanzar otro. Mientras el número de vacas lanzadas exceda k en la pregunta, entonces las condiciones no se cumplen.

4. Implementación del código

(Ver notas para más detalles)

 

#include<cstdio>
#include<iostream>
#include<algorithm>//sort必备
#include<climits>//这个是支持INT_MIN的头文件
using namespace std;
int n,k;
int x[(int)5e4+10];
//皆和题目中意义相同
bool check(int R)
{
    int s=0,now=INT_MIN;
    /*
    s表示已经发射了多少奶牛
    now表示当前已爆炸的范围
    为什么取INT_MIN呢,因为这样可以保证至少发射一头
    */
    for(register int i=1;i<=n;i++)
    {
        if(now<x[i]-R)
        {
            //如果当前已爆破的范围小于下一个能触及的范围
            s++;
            //发射数加1
            now=x[i]+R;
            //更新当前范围
            if(s>k)return false;
            //如果超过了限定数,那么就一定pass了
        }
    }
    return true;
    //到最后都没pass,说明成功爆破
}
int main()
{
    freopen("cpp.in", "r", stdin);
    freopen("cpp.out", "w", stdout);
    scanf("%d%d",&n,&k);
    for(register int i=1;i<=n;i++)
    {
        scanf("%d",&x[i]);
    }
    sort(x+1,x+n+1);
    int l=0,r=x[n];
    while(l<=r)
    {
        int mid=l+r>>1;
        if(check(mid))
        {
            r=mid-1;
        }
        else
        {
            l=mid+1;
        }
    }
    printf("%d\n",l);
    //二分模板
    return 0;
}

 

Código AC de mí

#include <iostream>
#include <cstdio>
#include <algorithm>
#define SIZE (int)1e4 * 5 + 10
#define INF 0x3f3f3f3f * 2
using namespace std;
int a[SIZE];

int my_search(const int &, const int &);
bool pan_duan(const int &, const int &, const int &);

int main() {
	freopen("cpp.in", "r", stdin);
	freopen("cpp.out", "w", stdout);
	int n, k;
	scanf("%d%d", &n, &k);
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &a[i]);
	}
	sort(a + 1, a + n + 1);
	printf("%d\n", my_search(n, k));
	return 0;
}

int my_search(const int &n, const int &k) {
	int left = 0, right = a[n];
	while (left <= right) {
		int mid = (left + right) >> 1;
		if (pan_duan(n, k, mid)) {
			right = mid - 1;
		} else {
			left = mid + 1;
		}
	}
	return left;
}
bool pan_duan(const int &n, const int &k, const int &R) {
	int num = 0, now = -INF;
	for (int i = 1; i <= n; ++i) {
		if (a[i] - R > now) {
			now = a[i] + R;
			++num;
			if (num > k) {
				return false;
			}
		}
	}
	return true;
}

 

Publicado 33 artículos originales · me gusta 0 · visitas 167

Supongo que te gusta

Origin blog.csdn.net/weixin_42790071/article/details/105539945
Recomendado
Clasificación