[Tarea de la semana 3] Problema de selección A, selección de punto de intervalo B, cobertura de intervalo C

Una pregunta de selección

Tema:

Dados n números positivos, ZJM puede seleccionar exactamente K de ellos que sumen a S. ¡Ahora ZJM se pregunta cuántas maneras de obtenerlo!

Entrada

La primera línea, un número entero T <= 100, indica el número de casos de prueba. Para cada caso, hay dos líneas. La primera línea, tres enteros indican n, K y S. La segunda línea, n enteros indican los números positivos.

Salida

Para cada caso, un número entero indica la respuesta en una línea independiente.

Entrada de muestra

1
10 3 10
1 2 3 4 5 6 7 8 9 10

Salida de muestra

4

Nota

Recuerde que k <= n <= 16 y todos los números se pueden almacenar en un entero de 32 bits

Ideas y prácticas:

Use el método de retroceso para resolver el problema.
Escriba una función de seguimiento y llame a esta función de forma recursiva hasta que alcance el límite u obtenga una solución válida y luego regrese. Primero escriba el código para hacer el conjunto de números posibles en el conjunto uno por uno para construir un conjunto de posibles soluciones. Es muy fácil implementar un bucle aquí. Primero, no repita directamente en la siguiente capa, coloque el número en la siguiente capa, y luego vuelva a repetir, y comprenda que el número está en línea con Hay dos casos de ausencia, y luego se puede acceder a todos los casos posibles. La clave es que para optimizar la complejidad del tiempo, necesitamos podar. Solo necesitamos números K, entonces no hay necesidad de continuar la recursión cuando el número en la matriz excede k; si la suma a satisfacer es menor que 0, significa que el número seleccionado ya es mayor que S y no cumple con los requisitos de la solución, regrese directamente; el acceso actual El índice del número ha excedido el rango de matriz dado, que es un límite que se devolverá. Si se encuentra una solución adecuada, regístrela y regrese directamente.
Una vez que finaliza toda la pista, el valor ans grabado es la respuesta.

Resumen:

Problema de retroceso muy básico, preste atención a cómo escribir funciones recursivas y cómo podar de manera efectiva.

Código:

#include <list>
#include <stdio.h>
using namespace std;
#define N 16
#define rep(i,s,t) for(int i=s;i<=t;i++)

list<int> nums;
int num[N],ans;

void backtrack(int start,int n,int k,int s){
	if(nums.size()==k&&s==0){
		ans++;
		return;
	}else if(nums.size()>k||s<0||start>=n){
		return;
	}else{
		rep(i,start,n-1){
			nums.push_back(num[i]);
			backtrack(i+1,n,k,s-num[i]);
			nums.pop_back();
		}
	}
}

int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int n,k,s;
		while(!nums.empty()) nums.pop_back();
		ans=0;
		scanf("%d %d %d",&n,&k,&s);
		rep(i,0,n-1){
			scanf("%d",&num[i]);
		}
		backtrack(0,n,k,s);
		printf("%d\n",ans);
	}
	return 0;
}

Selección de intervalo B

Tema:

Hay n intervalos cerrados [a_i, b_i] en la recta numérica. Tome la menor cantidad de puntos posible para que haya al menos un punto en cada intervalo (los puntos contenidos en diferentes intervalos pueden ser los mismos)

Entrada

1 entero N en la primera línea (N <= 100)
Línea 2 ~ N + 1, dos enteros a, b en cada línea (a, b <= 100)

Salida

Un número entero que representa el número de puntos seleccionados.

Entrada de muestra1

2
1 5
4 6

Salida de muestra1

1

Entrada de muestra2

3
1 3
2 5
4 6

Salida de muestra2

2

Ideas y prácticas:

Usa una estrategia codiciosa para resolver el problema de la selección de intervalos.
El primero es elegir un criterio codicioso y encontrar una solución basada en este criterio. El criterio codicioso utilizado aquí es ordenar desde el extremo más pequeño hasta el extremo derecho del intervalo. El primer pequeño significa que el intervalo termina antes y el siguiente intervalo termina tarde. Vea si el punto final izquierdo del siguiente intervalo está dentro del intervalo que está frente a él. En su extremo derecho, para cubrir este punto, y luego en bucle. Después de revisarlo nuevamente, el número de puntos es la solución.

Resumen:

Preste atención a la selección del criterio codicioso y piense en un criterio: si no puede lograr una prueba matemática, averigüe si hay un contraejemplo para derrocarlo. La guía para este tema es relativamente fácil: es posible utilizar un extremo variable para registrar el punto final derecho actual y seguir actualizándolo.

Código:

#include <stdio.h>
#include <algorithm>
#define N 100
using namespace std;

struct Interval{
	int a,b;
	Interval(){}
	Interval(int _a,int _b):a(_a),b(_b){}
	bool operator<(const Interval& i){
		return b<i.b;
	}
}interval[N];

int main(){
	int n,a,b;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d %d",&a,&b);
		interval[i]=Interval(a,b);
	}
	sort(interval,interval+n);
	int ans=1,end=interval[0].b;
	for(int i=1;i<n;i++){
		if(interval[i].a>end){
			ans++;
			end=interval[i].b;
		}
	}
	printf("%d\n",ans);
	return 0;
} 

Cobertura del intervalo C

Tema:

Hay n (1 <= n <= 25000) intervalos cerrados [ai, bi] en la recta numérica. Elija la menor cantidad de intervalos posible para cubrir un segmento de línea específico [1, t] (1 <= t <= 1,000,000).
Cubra todo el punto, es decir (1,2) + (3,4) puede cubrir (1,4).
Imposible hacer salida -1

Entrada

La primera línea: la
segunda línea de N y T a la línea N + 1: cada línea tiene un intervalo cerrado.

Salida

El número de intervalos seleccionados no se puede emitir -1

Entrada de muestra

3 10
1 7
3 6
6 10

Salida de muestra

2

Ideas y prácticas:

Se puede entender que se selecciona el número mínimo de celdas para cubrir un intervalo grande, y las celdas deben ser lo más largas posible, y se pueden cubrir de principio a fin para que se cubran con métodos codiciosos. En términos generales, dado un final de límite (el final inicial ubica el comienzo de un intervalo grande), necesitamos seleccionar el punto final izquierdo de los intervalos restantes a la izquierda del límite (si está a la derecha, está desconectado y no puede cubrirse por completo), y el punto final derecho está lejos de El intervalo más lejano (cuanto más larga sea la duración, el número total de intervalos correspondientes puede disminuir), luego actualice el final al extremo derecho del intervalo seleccionado (implementado específicamente en la función f, devuelve el valor de índice del intervalo más adecuado encontrado, no se puede encontrar Al retorno apropiado -1). Haga un bucle hasta que el extremo existente alcance o exceda el extremo derecho del amplio rango a cubrir, o no se encuentre una solución factible, y regrese a ans.

Resumen:

El primer pensamiento fue editar el intervalo desde el momento de la entrada, para clasificar y reciclar de acuerdo con el punto final izquierdo y la longitud del intervalo calculado, y actualizar el punto final izquierdo y la longitud entre cada celda de forma sincrónica en cada extremo de actualización. Más tarde, se descubrió que este problema también es fácil de cometer errores: la duración del intervalo ya no se calcula y la distancia entre el extremo derecho del intervalo y el final se compara directamente.

Código:

#include <stdio.h>
#include <algorithm>
#define N 25000
using namespace std;

struct Interval{
	int a,b;
	Interval(){}
	Interval(int _a,int _b):a(_a),b(_b){}
	bool operator<(const Interval& i) const{
		if(a!=i.a) return a<i.a;
		return b>i.b;
	}
}interval[N];

int f(int start,int end,int num){
	int ans=-1,min=-1;
	for(int i=start;i<end;i++){
		if(interval[i].a<=num+1&&interval[i].b>=num+1){
			if(interval[i].b-num-1>min){
				min=interval[i].b-num-1;
				ans=i;
			}
		}else if(interval[i].a>num+1) break;
	}
	return ans;
}

int main(){
	int n,t;
	while(~scanf("%d %d",&n,&t)){
		int cnt=0,a,b;
		for(int i=0;i<n;i++){
			scanf("%d %d",&a,&b);
//			if(a<=1&&b>=1&&b<=t) interval[cnt++]=Interval(1,b);
//			else if(b>t&&a>=1&&a<=t) interval[cnt++]=Interval(a,t);
//			else if(a>=1&&b<=t) interval[cnt++]=Interval(a,b);
//			else if(a<1&&b>t) interval[cnt++]=Interval(1,t);
			if(a<=t&&b>=1) interval[cnt++]=Interval(a,b);
		}
		sort(interval,interval+cnt);
		int ans=0,index=0,end=0;
		while(end<t){
			index=f(index,cnt,end);
			if(index==-1){  //没找到,断了 
				ans=-1;
				break;
			}
			ans++;  //找到,结果+1 
			end=interval[index].b;  //更新end 
		}
		printf("%d\n",ans);
	}
	return 0;
}
10 artículos originales publicados · Me gusta0 · Visitas 231

Supongo que te gusta

Origin blog.csdn.net/weixin_44898140/article/details/104852181
Recomendado
Clasificación