J'ai un site Web où les utilisateurs soumettent des questions (zéro, un ou plusieurs par jour), voter sur eux et répondent à une question par jour (plus de détails ici ). Un utilisateur peut voir la question seulement une fois en soumettant, votant ou en répondant. P>
J'ai un bassin de questions que les joueurs ont déjà vu. Je dois supprimer 30 questions de la piscine chaque mois. J'ai besoin de choisir des questions pour supprimer de cette manière que je maximisez le nombre de questions disponibles dans la piscine pour le joueur avec les questions les moins disponibles. P>
Exemple avec pool de 5 questions (et besoin de retirer 3): p>
Je pense à supprimer les questions que le haut joueur a vu, mais la position changerait. Après l'exemple ci-dessus, le joueur A n'a que 2 questions à jouer (2 et 4). Cependant, si je retire les 1, 3 et 5, la situation serait la suivante: p>
Le score pour cette solution est zéro, c'est-à-dire que le joueur avec moins de questions disponibles a zéro question de questions à jouer. p>
Dans ce cas, il serait préférable de supprimer les 1, 3 et 4, donner: p>
Le score de cette solution est un, car les deux joueurs ayant une quantité moindre quantité de questions disponibles à jouer ont une question disponible. P>
Si la taille de données était petite, je serais capable de brute la solution. Cependant, j'ai des centaines de joueurs et de questions, je cherche donc un algorithme pour résoudre ce problème. P>
10 Réponses :
Disons que vous souhaitez supprimer En plus de la matrice ci-dessus (que nous pouvons appeler "Score"), vous avez besoin d'une seconde avec des questions et des utilisateurs, où la traversée aura 1 si l'utilisateur a vu la question, et 0 s'il ne le faisait pas. Ensuite, pour chaque utilisateur, vous devez trouver Comme dernière étape, vous venez de supprimer Qu'est-ce que cet algorithme atteint également est que si la suppression de 30 questions fera que certains utilisateurs ont moins que N'hésitez pas à poser des questions si je n'ai pas décrit l'idée assez profonde. P> Y code> des questions de la piscine. L'algorithme simple serait de trier les questions de la quantité de vues qu'ils avaient. Ensuite, vous supprimez
y code> des questions de dessus visionnées. Pour votre exemple: 1: 2, 2: 1, 3: 1, 4: 2, 5: 1. Clairement, vous feriez mieux de supprimer les questions 1 et 4. Mais cet algorithme n'atteint pas l'objectif. Cependant, c'est un bon point de départ. Pour l'améliorer, vous devez vous assurer que chaque utilisateur se retrouvera avec au moins
x code> après le "nettoyage". P>
x cod> questions avec le score le plus bas
x code> de chaque utilisateur en troisième tableau, appelons-le "Safe", car nous ne supprimerons aucun de celui-ci. P>
y code> top visionné les questions (celles avec le score le plus élevé), qui ne sont pas dans le tableau "Safe". P>
x code> questions à afficher, il ne supprimera pas les 30. Ce qui est, je suppose, bien pour le système. P>
Idée intéressante. Disons que Y a 30 ans, comment déterminer la valeur pour x?
Vous spécifiez x code>, pas déterminez. Par exemple, vous pouvez commencer par
x = 1 code> et voir comment il s'avère, puis en exécutant l'algorithme pour
x = 2, 3, 4 code> Vous verrez à quelle vitesse le montant de questions vous pouvez supprimer des gouttes. À titre de note latérale, vous devez vraiment filtrer des utilisateurs «pas-actifs» pour cette idée pour fonctionner.
Avez-vous envisagé de regarder cela en termes d'une solution de programmation dynamique? P>
Je pense que vous pourrez peut-être le faire en optimisant sur le nombre de questions disponibles à gauche ouverte à tous les joueurs tels qu'aucun joueur n'a laissé avec zéro question ouverte. p>
Le lien suivant offre une bonne vue d'ensemble de la construction Programmation dynamique a > Solutions à ce type de problèmes. P>
Supposons que vous ayez un algorithme général efficace pour cela. Concentrez-vous sur les questions à gauche, plutôt que les questions supprimées. P>
Vous pouvez utiliser un tel algorithme pour résoudre le problème - pouvez-vous choisir au plus t des questions telles que chaque utilisateur a au moins une question à répondre? Je pense que c'est http://fr.wikipedia.org/wiki/set_cover , et je Pensez à résoudre votre problème en général vous permet de résoudre le couvercle défini, alors je pense que c'est NP-complet. P>
Il y a au moins une relaxation de programmation linéaire. Associer chaque question avec une variable qi dans la plage 0 <= qi <= 1. Choix des questions Qi de telle sorte que chaque utilisateur a au moins x questions disponibles montants disponibles à la contrainte SUM UIJ QJ> = x, qui est linéaire en qj et x, Vous pouvez donc optimiser la fonction objectif x avec les variables linéaires x et qj. Malheureusement, le résultat n'a pas besoin de vous donner entier QJ - considérez par exemple le cas lorsque toutes les paires de questions possibles sont associées à certains utilisateurs et que vous souhaitez que chaque utilisateur puisse répondre au moins 1 question, en utilisant au plus de la moitié des questions. La solution optimale est Qi = 1/2 pour tout i. P>
(mais donné une source de programmation linéaire, vous pouvez l'utiliser comme lié à http: //fr.wikipedia .org / wiki / sucaire_and_bound ). P>
Alternativement, vous pouvez simplement écrire le problème et le jeter dans un package de programmation linéaire entier, si vous avez une personne à portée de main. P>
J'ai utilisé GNU GLPK avant (GLPSOL) et je suis à l'aise d'écrire des problèmes dans le format .cplex, mais je semble être incapable d'écrire le problème. Voyons où je fais une erreur. Je crois que qi = 0 signifie que la question est supprimée et Qi = 1 signifie question reste. Mais comment puis-je écrire la fonction Maximize? Je souhaite maximiser le nombre de questions laissées pour l'utilisateur qui a moins de questions. Je ne sais pas comment écrire cela en tant que problème de programmation linéaire.
Notez que j'ai défini une variable supplémentaire X. ma fonction objectif n'est que la valeur de x: objectif (x, q1, q2 ...) = x. x est le nombre de questions pour l'utilisateur avec le moins, et c'est appliqué par la contrainte SUM_J UIJ QJ> = X. Ceci est l'une des premières astuces (section 6.2) dans Aimms.com/aimms/download/Manuals/...
Les articles Wikipedia ont déclaré que cela a été prouvé que la couverture définie ne peut être approximée de temps polynomial mieux que la simple approche gourmande. Est-ce que cela ne joue-t-il pas aussi ici et de faire une surkill d'une approximation basée sur la LP?
LP à l'intérieur de la branche et de la liaison, ou ILP, présente l'avantage sur la couverture de jeu gourmandise, si vous pouvez vous le permettre, de fournir une meilleure réponse connue. Lorsque vous êtes satisfait d'une réponse approximative bon marché, une recherche sur le Web suggère, via web .njit.edu / ~ Yang / Research / Covering / Covering.pdf , que l'ILP peut en effet être surchargé - merci.
La branche et la liaison pourrait utiliser toute approximation cependant. En supposant que cela soit réellement défini - couverture bien sûr. LPR est une belle tique cependant :)
présentant cela en termes de questions toujours jouables. Je trouverai les questions de 0 à 4 au lieu de 1 à 5, car cela est plus pratique dans la programmation.
void decide_one_question(int question_id , int questions_kept_so_far , upper_bound_on_the_score) { if(upper_bound_on_the_score < best_score_so_far) { // the upper bound is already too low, // therefore, this is a dead end. return; } if(question_id == 5) // .. continue with the rest of the function.
Voici un programme entier. Laissez constante invisible (i, j) code> être
1 code> si lecteur
i code> n'a pas vu la question
j code> et
0 code> sinon. Laissez la variable
conservée (j) code> être
1 code> si question
j code> doit être conservé et
0 code> sinon. Laissez la variable
score code> être l'objectif.
maximize score # score is your objective
subject to
for all i, score <= sum_j (unseen(i, j) * kept(j)) # score is at most
# the number of questions
# available to player i
sum_j (1 - kept(j)) = 30 # remove exactly
# 30 questions
for all j, kept(j) in {0, 1} # each question is kept
# or not kept (binary)
(score has no preset bound; the optimal solution chooses score
to be the minimum over all players of the number of questions
available to that player)
S'il y a trop d'options à la force brute et qu'il existe probablement de nombreuses solutions presque optimales (sonne comme le cas), considère les méthodes de Monte-Carlo. p>
Vous avez une fonction de fitness clairement définie, alors rendez-vous simplement des affectations aléatoires sur le résultat. Rincer et répéter jusqu'à ce que vous manquiez de temps ou que d'autres critères soient satisfaits. P>
La question semble d'abord facile, mais après avoir pensé plus loin que vous réalisez la dureté. P>
L'option la plus simple supprimerait les questions observées par nombre maximum d'utilisateurs. Mais cela ne prend pas le nombre de questions restantes pour chaque utilisateur en considération. Certaines questions peuvent être laissées pour certains utilisateurs après avoir retiré. P>
Une solution plus complexe comporterait le nombre de questions restantes pour chaque utilisateur après avoir supprimé une question. Vous devez le calculer pour chaque question et chaque utilisateur. Cette tâche peut consommer du temps si vous avez de nombreux utilisateurs et questions. Ensuite, vous pouvez résumer le nombre de questions à gauche pour tous les utilisateurs. Et sélectionnez la question avec la somme la plus élevée. P>
Je pense qu'il serait sage de limiter le nombre de questions restantes à un utilisateur à une valeur raisonnable. Vous pouvez penser "OK, cet utilisateur a suffisamment de questions à afficher s'il a plus de x questions". Vous en avez besoin, car après avoir supprimé une question, seules 15 questions peuvent être laissées pour un utilisateur actif tandis que 500 questions peuvent être laissées pour un utilisateur de visites rares. Ce n'est pas juste de la somme 15 et 500. Vous pouvez plutôt définir une valeur seuil de 100. P>
Pour que cela soit plus facile à calculer, vous ne pouvez considérer que les utilisateurs qui ont visionné plus de questions x. P>
En fait, vous ne seriez à considérer que des utilisateurs qui ont laissé 60 questions ou moins.
modèles de programmation linéaire.
dans ce cas , Le problème LP est plus simple, mais (Éventuellement) Utilisez une recherche binaire pour déterminer la limite supérieure de la solution exacte de la solution code> p> à partir du meilleur code> Score code>, trouvé par la recherche binaire, appliquez-la entier Algorithme LP avec Voici un exemple de code en C pour GNU GLPK (pour variante 1): p> uij code> est
1 Code> Si l'utilisateur
i code> n'a pas vu la question
j code>, sinon il est
0 code> p>
dij code > Est-ce élément de matrice d'identité (
dij = 1 code> si
i = j code>, sinon il est
0 code>) p>
Xj code> est une variable auxiliaire (une pour chaque utilisateur) p>
score code> doit être déterminé par la recherche binaire et linéaire. Définissez la plage de courant sur [0 .. Le moins de questions invisibles pour un utilisateur], définissez «Code> Score code> au milieu de la plage, appliquez l'algorithme INTEGER LP (avec une petite limite de temps). Si aucune solution n'a été trouvée, réglez la plage de [COMMEND ..
SCORE CODE>], sinon réglez-le sur [
Score code> .. fin] et poursuivez la recherche binaire. P>
Score Code>, augmenté de 1, 2, ...
(et limiter le temps de calcul si nécessaire). À la fin, vous obtenez une solution exacte, soit une bonne approximation. P>
#include <stdio.h>
#include <stdlib.h>
#include <glpk.h>
int main(void)
{
int ind[3000];
double val[3000];
int row;
int col;
glp_prob *lp;
// Parameters
int users = 120;
int questions = 10000;
int questions2 = questions - 30;
double score = 4869.0 + 7;
// Create GLPK problem
lp = glp_create_prob();
glp_set_prob_name(lp, "questions");
glp_set_obj_dir(lp, GLP_MAX);
// Configure rows
glp_add_rows(lp, users + 1);
for (row = 1; row <= users; ++row)
{
glp_set_row_bnds(lp, row, GLP_LO, score, score);
}
glp_set_row_bnds(lp, users + 1, GLP_FX, questions2, questions2);
// Configure columns
glp_add_cols(lp, questions);
for (col = 1; col <= questions; ++col)
{
glp_set_obj_coef(lp, col, 0.0);
glp_set_col_kind(lp, col, GLP_BV);
}
// Configure matrix (question columns)
for(col = 1; col <= questions; ++col)
{
for (row = 1; row <= users; ++row)
{
ind[row] = row;
val[row] = (rand() % 2)? 1.0: 0.0;
}
ind[users + 1] = users + 1;
val[users + 1] = 1.0;
glp_set_mat_col(lp, col, users + 1, ind, val);
}
// Solve integer GLPK problem
glp_iocp param;
glp_init_iocp(¶m);
param.presolve = GLP_ON;
glp_intopt(lp, ¶m);
glp_delete_prob(lp);
return 0;
}
Si je comprends bien, je ne devrais remplacer que Rand () avec 0 ou 1 selon que l'utilisateur a vu la question ou non. La boucle intérieure pour () monte aux utilisateurs * 2 Je ne suis donc pas sûr de quoi placer là-bas. Supposant que j'ai eu une fonction qui retourne 1 ou 0 comme ceci: INT user_seen_question (utilisateur international, int question), comment puis-je remplacer Rand () avec cette fonction?
Question de Variante 2: D'où vient 4869.0?
Remplacer (rand ()% 2)? 1.0: 0.0 code> à
user_seen_question (utilisateur int, in int question)? 0.0: 1.0 code>. Vous pouvez également remplacer
questions2 code> et (pour variante 2)
score code>. Toutes les autres valeurs sont
celles code> et
zeros code>, utilisées pour une matrice d'identité, des variables ignorées et des questions à compter, ne les changent pas. En fait, tous les coefficients de matrice dans les échantillons sont exactement dans le même ordre que dans des descriptions de modèle en haut de ma réponse.
4869.0 et 4869.0 + 7 sont des résultats de la recherche binaire que j'ai faite manuellement. 4869.0 est le meilleur score approximatif. 4869.0 + 7 est le score le plus bas, ce qui rend définitivement le problème infaisable. La valeur exacte est quelque part entre les deux. Si vous avez une implémentation de RNG différente, vous obtiendrez des valeurs différentes pour le score.
Dans vos exemples, les variables sont "rangées" et "col", pas "utilisateur" et "question". En Variant2, il est facile, au lieu de rand () J'écris user_seen_question (rangée, col). Mais, quoi écrire en variante 1 lorsque la ligne peut être 2 * utilisateurs?
Ce score 4869 dépend-il du nombre d'utilisateurs et de questions ou est-il une valeur fixe?
Pour la première moitié des rangées, vous écrivez ! User_seen_question () code>, comme d'habitude. La seconde moitié des rangées ont des zéros dans ces colonnes. En d'autres termes, changez
((rangée <= utilisateurs) && (rand ()% 2))? 1.0: 0.0; code> à
((ligne <= utilisateurs) &&! User_seen_question (utilisateur, question))? 1.0: 0.0; code>.
Oui, le score 4869 dépend des données d'entrée, du nombre d'utilisateurs, des questions, des questions supprimées, sur user_seen_question (). Vous pouvez vous procurer cette valeur vous-même, en commençant par les questions moins invisibles et faire une recherche binaire. Pour cet exemple, vous devrez écrire sur Log (n) différentes constantes dans cet endroit, recompiler et courir pour chacune d'elles. Dans le programme réel, cela devrait être fait automatiquement.
Merci. Je vais attribuer la prime maintenant parce que le délai est atteint, mais j'aurais peut-être d'autres questions lorsque j'essaie de la mettre en œuvre au cours des prochains jours.
N'hésitez pas à demander quoi que ce soit. Juste quelques conseils. @dhakim propose plusieurs étapes d'optimisation. Essayez les. Peut être PRESOLVER GLPK fait déjà tout cela. Peut être pas. Pour (Variant 2) Recherche automatique du score, il peut être plus pratique (mais moins portable) pour démarrer un processus distinct pour chaque étape de recherche. Et tuer des processus inachevés après un délai d'attente. Étant donné que l'avoir plus de 2 processeur de base est assez habituel de nos jours, vous pouvez démarrer 2+ processus de solvement LP à la fois pour obtenir la recherche ternaire + la recherche au lieu de binaire et pour effectuer plusieurs étapes de recherche linéaire à la fois.
En fin de compte, j'ai utilisé une variante 1. Il calcule la solution pour mon problème en environ 30 secondes, ce qui est tout à fait bien depuis que je ne l'exécute qu'une fois par mois. Merci encore.
N'oubliez pas de tester avec des tailles de problèmes plus importantes. INTEGER GLPK Solver utilise un algorithme de branche et coupé, qui a une complexité exponentielle.
30 secondes est le temps nécessaire pour résoudre le problème dans la production: 144 questions et 657 utilisateurs pour janvier.
Mais plusieurs mois plus tard, il peut s'agir de 500 questions / 800 utilisateurs. Ou plus.
Les utilisateurs se situent entre 600 et 700 pendant plus d'un an. S'il y avait 500 questions, je serais très heureux et vient facilement de choisir 30 de la piscine car la cueillette ne serait plus si pertinente. Le fait est que 4 à 5 utilisateurs passionnés ont connu beaucoup plus de questions que le reste de la foule, donc si j'avais 500 questions, je ne calculerais probablement probablement que le modèle pour ces 5 utilisateurs. La raison pour laquelle j'ai besoin de calcul précis est parce qu'il n'y a pas beaucoup de questions dans la piscine.
Pour l'exhaustivité du thread, voici une simple approche gourmande et avide.
Placez les questions résolues dans la forme matricielle précédemment discutée: p> Trier par le Nombre de questions résolues: p> frappe une question avec le plus Trier à nouveau: P> x code> s parmi les joueurs avec la plupart des problèmes résolus. (Ceci est garanti de diminuer notre mesure si quelque chose est): p>
Q0 X
Q1 X
Q2 XXX
Q3 XXX
Q4 XXXX
Q5 222222
Je propose un tas d'optimisations basé sur l'idée que vous souhaitez vraiment maximiser le nombre de questions invisibles pour le joueur avec le nombre minimum de questions et ne vous souciez pas s'il ya 1 joueur avec le nombre minimum de questions ou 10000 joueurs avec ce même nombre de questions. p>
Étape 1: Trouvez le joueur avec le nombre minimum de questions invisible (dans votre exemple, ce serait le joueur A) appeler ce lecteur p. P>
Étape 2: Trouvez tous les joueurs avec moins de 30 des questions invisibles par le joueur p. Appelez cet ensemble P. P sont les seuls joueurs qui doivent être pris en compte, car la suppression de 30 questions invisibles de tout autre joueur leur laisserait toujours des questions plus invisibles que le joueur p et que le joueur P serait toujours pire. p>
Étape 3: Trouvez l'intersection de tous les ensembles de problèmes observés par les joueurs dans P, vous pouvez supprimer tous les problèmes de cet ensemble, vous, espérons-le, vous laisser tomber de 30 à un plus petit nombre de problèmes à supprimer, que nous appellerons r. r <= 30 p>
Étape 4: Trouvez l'union de tous les ensembles de problèmes observés par les joueurs de P, appelez cet ensemble U. Si la taille de U est <= R, vous avez terminé, supprimez tous les problèmes de vous, puis enlevez les problèmes restants. Arbitrairement de votre ensemble de tous les problèmes, le joueur P perdra R - Taille de vous et restera avec les plus petits problèmes invisibles, mais c'est le meilleur que vous puissiez faire. P>
Vous êtes maintenant laissé avec votre problème d'origine, mais probablement avec des ensembles de vastes plus petits.
Votre jeu de problèmes est U, votre jeu de joueur est P, et vous devez supprimer des problèmes. p>
L'approche de la force brute prend du temps (taille (U) choisit R) * Taille (P). Si ces chiffres sont raisonnables, vous pouvez simplement la force de brute. Cette approche est de choisir chaque ensemble de problèmes de vous et de l'évaluer contre tous les joueurs de P. P>
Étant donné que votre problème semble être NP-complet, le meilleur que vous puissiez probablement espérer est une approximation. Le moyen le plus simple de le faire est de définir un nombre maximum d'essais, puis choisissez et évaluez au hasard des ensembles de problèmes à supprimer. En tant que telle, une fonction pour effectuer u choisir r au hasard devient nécessaire. Cela peut être fait dans le temps O (R) (en fait, j'ai répondu à la façon de le faire plus tôt aujourd'hui!) P>
Sélectionnez N éléments aléatoires d'une liste
Vous pouvez également mettre l'une des heuristiques suggérées par d'autres utilisateurs dans vos choix en pondant la chance de chaque problème d'être sélectionné, je pense que le lien ci-dessus montre comment faire cela dans la réponse sélectionnée. p>
Pourquoi supprimer des questions du tout? Pourquoi éliminer exactement 30 questions par mois?
Il existe deux groupes de joueurs: joueurs qui jouent pour classement et joueur qui jouent simplement pour le plaisir. Les joueurs qui jouent pour classement doivent avoir des questions uniques, c'est pourquoi la cachette est nécessaire. Chaque mois 30 questions sont retirées des joueurs classés - pool en piscine publique-forêt. Donc, il n'y a pas vraiment 30, mais autant qu'il y a des jours dans un mois donné.
Pourquoi ne pas simplement enlever la question la plus ancienne des joueurs classés-piscine?
Le fait qu'ils soient aînés ne signifie pas que cela a été vu par la plupart des joueurs. En fait, l'âge de la question est totalement sans rapport avec le problème. Cela pourrait facilement arriver que tous les joueurs ont été observés par tous les joueurs de ce jour-là, tandis que la question ajoutée au jour 1 n'a été observée que par 4-5 joueurs.
Pourquoi est-il important quelle question est vue par quel nombre de joueurs? Toutes les questions vont être progressivement éliminées. Il est logique de le faire la FIFO WAY. Si cela se produit tellement que certaines questions sont perçues par un très grand nombre de joueurs, c'est probablement une question populaire et un nouveau joueur voudrait probablement y répondre également.
Il n'y a pas de questions «populaires», elles sont assignées de manière totalement aléatoire de la piscine.
Ensuite, la probabilité qu'une question ait beaucoup plus de réponses que toutes les autres est très faible (compensation de l'âge de la question) et ne vaut pas les efforts déployés pour atténuer. Mais si c'est tellement un problème, pourquoi ne pas simplement supprimer la question avec la plupart des réponses, au lieu de supprimer la question la plus ancienne?
Les réponses ne sont qu'une petite partie du puzzle. Ce qui est important, ce sont des vues. Si vous regardez ma précédente question associée (lien est ci-dessus dans le texte), vous verrez que certains joueurs ont vu beaucoup de questions tout en les examinant. Prenons, par exemple, le joueur A qui a examiné 40 questions et a répondu à 30 questions pendant un mois VS Player B qui a récemment rejoint le site Web et n'a joué que 15 questions ce mois-ci avec 0 avis. De toute évidence, des questions que le joueur A n'a pas encore vu sont plus utiles et ne devraient pas être libérés de la piscine, quel que soit leur âge.
J'ai supposé que les anciennes questions sont supprimées pour faire de la place à de nouvelles questions. Dans ce cas, il n'y a pas de mal à supprimer une question ancienne, car une nouvelle est à venir. La nouvelle question est-elle disponible lorsque l'ancien est enlevé? Quelle serait la raison de cette question d'être si "privilégiée" de rester dans la piscine plus longtemps que tous les autres? Peut-être que vous devriez avoir une autre piscine de meilleures questions populaires?
La disponibilité de nouvelles questions dépend de la question de savoir si les utilisateurs les envoient ou non. Il n'est pas certain que nous aurons de nouvelles questions lorsque nous en supprimons. Pour cette raison, l'élimination doit faire attention. Quant à la deuxième partie de votre commentaire: toutes les questions sont traitées de manière égale.
Supprimez-vous une question tous les jours ou enlevez-vous toutes les trente questions à la fin du mois?
Je soupçonne que vous obtiendrez une assez bonne, rapide et facile d'approximation en supprimant à plusieurs reprises une question répondant par le joueur avec les plus petites questions libres dans le jeu restant. Peut-être choisir la question avec la plupart des réponses en cas de multiples choix disponibles.
Supprimer les 30 ans en fin de mois.
Dans ce cas, vous pouvez limiter votre problème à seuls les utilisateurs qui ont moins de 60 questions laissées invisibles. Ce sont les seuls qui risquent de disposer de zéro questions pour ce mois-ci si 30 questions sont supprimées. Depuis combien de questions totales parlons-nous? Et combien d'utilisateurs totaux?
Actuellement sur environ 80 questions et 650 utilisateurs.
@Joelcornett, limitant le problème des utilisateurs avec moins de 60 questions est inutile. Mais ce sera une bonne optimisation pour limiter le problème aux utilisateurs ayant une différence de moins de 30 de l'utilisateur avec un nombre minimal de questions à gauche.
@Evgenykluev Peut-être que je ne vois pas ce que tu veux dire. Pour autant que je puisse dire, 60 questions libres sont le minimum qu'un utilisateur peut avoir à assurer une possibilité que d'un utilisateur soit laissé avec moins de 30 questions (1 par jour) pour les 30 prochains jours. Par conséquent, ceux avec moins de 60 questions sont les seuls à risquer d'avoir une pénurie de questions une fois que les 30 questions sont supprimées. Ils sont le seul groupe d'intérêts.
@Joelcorntt, il n'est pas nécessaire de réserver exactement 30 questions pour le mois prochain. Une telle exigence est soit trop difficile (car les utilisateurs peuvent obtenir de nouvelles questions au tout début du mois prochain) ou trop molle (en cas de nouvelles questions pour les 32 prochaines jours).
En parlant d'optimisations, il peut être utile de filtrer des questions «invisibles», communes à tous les utilisateurs. Peut-être que LP Presolver le fera de toute façon. Mais pour les algorithmes de force brute et de heuristique, cela aidera.