tema
Eva gosta de coletar moedas de todo o universo.
Um dia, ela foi a um shopping center do universo para fazer compras e poderia usar várias moedas para pagar no caixa.
Porém, há uma exigência especial de pagamento: para cada nota, ela só pode usar exatamente duas moedas para pagar com precisão o valor do consumo.
Dadas as denominações de todas as moedas que ela possui, ajude-a a determinar se ela pode encontrar duas moedas para pagar a quantia fornecida.
Formato de entrada A
primeira linha contém dois inteiros N e M, que representam respectivamente o número de moedas e o valor a ser pago.
A segunda linha contém N inteiros, representando a denominação de cada moeda.
Formato de
saída Produz uma linha, contendo dois inteiros V1, V2, representando as denominações das duas moedas selecionadas, tais que V1≤V2 e V1 + V2 = M.
Se a resposta não for única, a solução com o menor V1 será produzida.
Se não houver solução, imprima No Solution.
Faixa de dados
1≤N≤105,
1≤M≤1000
Exemplo de entrada 1:
8 15
1 2 8 7 2 4 11 15
Exemplo de saída 1:
4 11
Exemplo de entrada 2:
7 14
1 8 7 2 4 11 15
Amostra de saída 2:
Sem solução
O que é um algoritmo de ponteiro duplo?
Introdução O
algoritmo de ponteiro duplo é amplamente usado e pode ser usado como um algoritmo mais eficiente porque fixa alguma ordem para itens de combinação e exclui diretamente algumas opções de combinação em comparação com a pesquisa de força bruta comum. A ideia é que cada um dos dois ponteiros, um ponteiro seja responsável pelo loop, e o outro ponteiro seja responsável por verificar as condições e cooperar.
modelo
for (int i = 0, j = 0; i < n; i ++ )
{
while (j < i && check(i, j)) j ++ ;
// 具体问题的逻辑
}
常见问题分类:
(1) 对于一个序列,用两个指针维护一段区间
(2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作
Quais são as condições de uso?
Onde o algoritmo de dois ponteiros pode ser usado, ele pode ser resolvido violentamente. Primeiro, apresentamos uma solução violenta e, em seguida, consideramos o uso do algoritmo de dois ponteiros para otimização. Se ponteiros duplos podem ser usados para manter um intervalo, então este intervalo deve ser monotônico . Porque somente quando a monotonicidade é satisfeita, podemos fixar alguma ordem para os itens de combinação e excluir diretamente outras opções de combinação.
Ideias para resolução de problemas
Para este problema, primeiro encontre uma solução violenta.
for (int i = 0; i < n; i++)
{
for (int j = 0; j < i; j++)
{
if (a[i] + a[j] == m) //更新答案
{
}
}
}
A complexidade do tempo é O(n^2)
muito fácil.
Considere a otimização de algoritmo de ponteiro duplo
Classifique a matriz primeiro para torná-la ordenada .
Em seguida, defina dois ponteiros i
, j
. i
Aponte para o início da matriz, j
aponte para o final da matriz.
Quando os dois ponteiros não se cruzam e a a[i]+a[j]>m
descrição é a[j]
ampliada, move-se para o j
ponteiro esquerdo e, portanto, o número de dois a[i] +a[j]
é reduzido. Essa execução while (i<j&&a[i] + a[j]>m) j--;
até a[i]+a[j]<=m
sair do loop.
Então o julgamento a[i] +a[j]
é igual m
, se não for igual à descrição a[i]
menor, mova i
o ponteiro, de modo que dois números a[i] +a[j]
aumentem.
Continue até a operação acima a[i] +a[j] ==m
, registramos as respostas.
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)
{
//记录答案
}
}
Como o i
ponteiro ou os j
ponteiros podem ser movidos em uma direção, i++
ou j--
executados na maioria das n
vezes, a complexidade do tempo é 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;
}