AcWing 1532. Encuentra monedas [Explicación detallada del algoritmo de puntero doble]

tema

A Eva le gusta coleccionar monedas de todo el universo.

Un día, fue a un centro comercial del universo a comprar y pudo usar varias monedas para pagar en la caja.

Sin embargo, hay un requisito de pago especial: por cada billete, solo puede usar exactamente dos monedas para pagar el monto del consumo con precisión.

Dadas las denominaciones de todas las monedas que tiene, ayúdela a determinar si puede encontrar dos monedas para pagar la cantidad dada.

Formato de entrada La
primera línea contiene dos números enteros N y M, que representan respectivamente el número de monedas y el monto a pagar.

La segunda línea contiene N números enteros, que representan la denominación de cada moneda.

Formato de
salida Salida de una línea, que contiene dos números enteros V1, V2, que representan las denominaciones de las dos monedas seleccionadas, de modo que V1≤V2 y V1 + V2 = M.

Si la respuesta no es única, se emite la solución con el V1 más pequeño.

Si no hay solución, envíe No Solution.

Rango de datos
1≤N≤105,
1≤M≤1000
Ejemplo de entrada 1:
8 15
1 2 8 7 2 4 11 15
Ejemplo de salida 1:
4 11
Ejemplo de entrada 2:
7 14
1 8 7 2 4 11 15
Muestra de salida 2:
Sin solución

¿Qué es un algoritmo de puntero dual?

Introducción El
algoritmo de puntero dual se usa ampliamente y se puede usar como un algoritmo más eficiente porque fija algún orden para los elementos de combinación y excluye directamente algunas opciones de combinación en comparación con la búsqueda de fuerza bruta ordinaria. La idea es que cada uno de los dos punteros, un puntero es responsable del bucle y el otro puntero es responsable de verificar las condiciones y cooperar.
modelo

for (int i = 0, j = 0; i < n; i ++ )
{
    
    
    while (j < i && check(i, j)) j ++ ;

    // 具体问题的逻辑
}
常见问题分类:
    (1) 对于一个序列,用两个指针维护一段区间
    (2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作

¿Cuáles son las condiciones de uso?

Cuando se puede usar el algoritmo de dos punteros, se puede resolver violentamente. Primero se nos ocurre una solución violenta y luego consideramos usar el algoritmo de dos punteros para la optimización. Si se pueden usar punteros duales para mantener un intervalo, este intervalo debe ser monótono . Porque solo cuando se satisface la monotonicidad, podemos fijar algún orden para los elementos de combinación y excluir directamente otras opciones de combinación.

Ideas para resolver problemas

Para este problema, primero busque una solución violenta.

for (int i = 0; i < n; i++)
{
    
    
	for (int j = 0; j < i; j++)
	{
    
    
		if (a[i] + a[j] == m) //更新答案
		{
    
    
		
		}
	}
}

La complejidad del tiempo es O(n^2)muy fácil.

Considere la optimización del algoritmo de doble puntero

Primero, ordena la matriz para que quede ordenada .

A continuación, defina dos punteros i, j. iApunta al principio de la matriz, japunta al final de la matriz.
Inserte la descripción de la imagen aquí

Cuando el puntero dos no se cruza y la a[i]+a[j]>mdescripción se a[j]toma grande, se mueve hacia el jpuntero izquierdo , por lo que a[i] +a[j]se reduce el número de dos . Esa ejecución while (i<j&&a[i] + a[j]>m) j--;hasta a[i]+a[j]<=msalir del bucle.

Entonces el juicio a[i] +a[j]es igual m, si no es igual a la descripción a[i]tomada más pequeña, mueva iel puntero, de modo que a[i] +a[j]aumenten dos números .

Continuar hasta la operación anterior a[i] +a[j] ==m, registramos las respuestas.

	sort(a, a + n);
	for (int i = 0, j = n - 1; i < j; i++)
	{
    
    
		while (i<j&&a[i] + a[j]>m) j--;
		if (i < j&&a[i] + a[j] == m)
		{
    
    
			//记录答案
		}
	}

Dado que el ipuntero o los jpunteros se pueden mover en una dirección i++o j--realizar la mayoría de las nveces, la complejidad del tiempo es O(n).

Código completo

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int main()
{
    
    
	int n, m;
	cin >> n >> m;
	for (int i = 0; i < n; i++) cin >> a[i];
	int v1, v2, flag = 0;
	sort(a, a + n);
	for (int i = 0, j = n - 1; i < j; i++)
	{
    
    
		while (i<j&&a[i] + a[j]>m) j--;
		if (i < j&&a[i] + a[j] == m)
		{
    
    
			v1 = a[i];
			v2 = a[j];
			flag = 1;
			break;
		}
	}
	if (flag) cout << v1 << ' ' << v2 << endl;
	else cout << "No Solution" << endl;
	return 0;
}

Supongo que te gusta

Origin blog.csdn.net/weixin_45629285/article/details/112802387
Recomendado
Clasificación