AcWing 1532. Encontrar moedas [explicação detalhada do algoritmo de ponteiro duplo]

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. iAponte para o início da matriz, japonte para o final da matriz.
Insira a descrição da imagem aqui

Quando os dois ponteiros não se cruzam e a a[i]+a[j]>mdescrição é a[j]ampliada, move-se para o jponteiro 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]<=msair do loop.

Então o julgamento a[i] +a[j]é igual m, se não for igual à descrição a[i]menor, mova io 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 iponteiro ou os jponteiros podem ser movidos em uma direção, i++ou j--executados na maioria das nvezes, 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;
}

Acho que você gosta

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