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
. i
Apunta al principio de la matriz, j
apunta al final de la matriz.
Cuando el puntero dos no se cruza y la a[i]+a[j]>m
descripción se a[j]
toma grande, se mueve hacia el j
puntero 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]<=m
salir 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 i
el 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 i
puntero o los j
punteros se pueden mover en una dirección i++
o j--
realizar la mayoría de las n
veces, 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;
}