{"id":35406,"date":"2019-10-31T22:04:08","date_gmt":"2019-10-31T19:04:08","guid":{"rendered":"https:\/\/prohoster.info\/blog\/kak-reshat-np-trudnye-zadachi-s-pomoshhyu-parametrizovannyh-algoritmov\/"},"modified":"2021-01-02T13:01:41","modified_gmt":"2021-01-02T11:01:41","slug":"kak-reshat-np-trudnye-zadachi-s-pomoshhyu-parametrizovannyh-algoritmov","status":"publish","type":"post","link":"https:\/\/prohoster.info\/it\/blog\/news\/kak-reshat-np-trudnye-zadachi-s-pomoshhyu-parametrizovannyh-algoritmov","title":{"rendered":"Come risolvere problemi NP-difficili con algoritmi parametrizzati","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Il lavoro di ricerca scientifica \u00e8, senza dubbio, la parte pi\u00f9 interessante del nostro percorso formativo. L'idea \u00e8 di provare gi\u00e0 all'universit\u00e0 a cimentarsi nella propria area di specializzazione. Ad esempio, gli studenti delle specializzazioni in Ingegneria del Software e Machine Learning spesso svolgono progetti di ricerca in aziende (principalmente JetBrains o Yandex, ma non solo).<\/p>\n<p>In questo post parler\u00f2 del mio progetto nel campo della Computer Science. Nell'ambito del lavoro ho studiato e implementato nella pratica approcci alla soluzione di uno dei problemi NP-difficili pi\u00f9 noti: <b>il problema della copertura dei vertici<\/b>.<\/p>\n<p>Attualmente si sta sviluppando molto rapidamente un interessante approccio ai problemi NP-difficili: gli algoritmi parametrizzati. Cercher\u00f2 di introdurvi a questa tematica, illustrando alcuni semplici algoritmi parametrizzati e descrivendo un potente metodo che mi \u00e8 stato molto utile. Ho presentato i miei risultati alla competizione PACE Challenge: in base ai test aperti, la mia soluzione occupa il terzo posto, mentre i risultati finali saranno noti il 1\u00b0 luglio.<\/p>\n<p><img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/177a2a930966b9df8ec00e898af024b3.png\" style=\"display:block;margin: 0 auto;\"><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3>Chi sono<\/h3>\n<p>Mi chiamo Vasili Alferov, e attualmente sto concludendo il terzo anno all'HSE \u2014 San Pietroburgo. Sono appassionato di algoritmi sin dai tempi della scuola, quando studiavo alla scuola 179 di Mosca e partecipavo con successo alle olimpiadi di informatica.<\/p>\n<h3>Un numero finito di specialisti di algoritmi parametrizzati entra in un bar&#8230;<\/h3>\n<p><i>L'esempio \u00e8 tratto dal libro <noindex><a rel=\"nofollow\" href=\"https:\/\/link.springer.com\/book\/10.1007%2F978-3-319-21275-3\">\u00abParameterized algorithms\u00bb<\/a><\/noindex><\/i><\/p>\n<p>Immaginate di essere un guardiano di un bar in una piccola citt\u00e0. Ogni venerd\u00ec, met\u00e0 della citt\u00e0 viene nel vostro bar per rilassarsi, il che vi causa non pochi problemi: dovete espellere i clienti indisciplinati per evitare risse. Alla fine, vi stancate di questo e decidete di prendere misure preventive.<\/p>\n<p>Poich\u00e9 la citt\u00e0 \u00e8 piccola, sapete esattamente quali coppie di clienti hanno una grande probabilit\u00e0 di litigare se si trovano nello stesso bar. Avete un elenco di <i>n<\/i> persone che verranno questa sera nel bar. Decidete di non far entrare alcuni cittadini in modo tale che nessuno si tiri in rissa. Allo stesso tempo, i vostri superiori non vogliono perdere guadagni e saranno insoddisfatti se non farai entrare pi\u00f9 di <i>k<\/i> persone.<\/p>\n<p>Sfortunatamente, il compito che vi trovate ad affrontare \u00e8 un classico problema NP-difficile. Potreste conoscere questo problema come <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Vertex_cover\">Vertex Cover<\/a><\/noindex>, o come un problema di copertura dei vertici. Per questi problemi, in generale, non si conoscono algoritmi che funzionino in tempi accettabili. A essere precisi, l'ipotesi ETH (Exponential Time Hypothesis), non dimostrata e piuttosto forte, afferma che questo problema non pu\u00f2 essere risolto in un tempo <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/03fdffad06e7b9e625bd0d0eee0e827f.png\" style=\"display:block;margin: 0 auto;\">, cio\u00e8 che non si pu\u00f2 pensare a nulla di significativamente migliore della ricerca esaustiva. Ad esempio, supponiamo che nel tuo bar stia per arrivare <i>n = 1000<\/i> persone. Quindi, la ricerca esaustiva comporterebbe <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/5b1c0116cd6a222126b86bc5c601d171.png\" style=\"display:block;margin: 0 auto;\"> opzioni, che sono circa <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/f37af5f2005709ac282f091576540e4d.png\" style=\"display:block;margin: 0 auto;\"> \u2014 esageratamente molte. Per fortuna, la tua direzione ti ha imposto un limite <i>k = 10<\/i>, cos\u00ec il numero di combinazioni che devi esaminare \u00e8 molto inferiore: il numero di sottoinsiemi di dieci elementi \u00e8 <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/4f618bd2bcbaea1d2ab1e3924629897e.png\" style=\"display:block;margin: 0 auto;\">. \u00c8 gi\u00e0 meglio, ma comunque non sar\u00e0 possibile contarli in un giorno, nemmeno su un potente cluster.<br \/>\n<img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/fc9753cb43ee44a189766413779e4422.png\" style=\"display:block;margin: 0 auto;\"><br \/>\nPer escludere la possibilit\u00e0 di risse con una tale configurazione di relazioni tese tra i clienti del bar, \u00e8 necessario non far entrare Bob, Daniel e Fyodor. Non esiste una soluzione in cui solo due rimangano fuori.<\/p>\n<p>Significa che \u00e8 ora di arrendersi e far entrare tutti? Consideriamo altre opzioni. Ad esempio, si pu\u00f2 non far entrare solo coloro che potrebbero probabilmente litigare con un numero molto elevato di persone. Se qualcuno pu\u00f2 litigare con almeno <i>k + 1<\/i> altre persone, allora non pu\u00f2 essere sicuramente fatto entrare \u2014 altrimenti dovr\u00e0 essere escluso da tutti <i>k + 1<\/i> i cittadini con cui potrebbe litigare, il che sicuramente deluder\u00e0 la direzione.<\/p>\n<p>Supponiamo che tu abbia escluso tutti coloro che potevi seguendo questo principio. Allora tutti gli altri possono litigare con non pi\u00f9 di <i>k<\/i> persone. Escludendo da loro <i>k<\/i> persone, puoi prevenire al massimo <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/2212d20b6f0031f25f2ed64223b9aad8.png\" style=\"display:block;margin: 0 auto;\"> conflitti. Quindi, se pi\u00f9 di <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/80c7d6b508268dea665de99d0dea0348.png\" style=\"display:block;margin: 0 auto;\"> persone partecipano ad almeno un conflitto, sicuramente non potrai prevenirli tutti. Dato che, ovviamente, le persone completamente non conflittuali le farai entrare, dovrai esaminare tutti i sottoinsiemi di dieci delle duecento persone. Sono circa <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/2974459582e8ff24b92a723394502f31.png\" style=\"display:block;margin: 0 auto;\">, e un numero di operazioni del genere \u00e8 gi\u00e0 possibile da esaminare su un cluster.<\/p>\n<p>Se \u00e8 possibile accogliere persone del tutto non conflittuali, che dire di quelli che partecipano solo a un conflitto? In realt\u00e0, anche loro possono essere accolti, chiudendo la porta di fronte al loro avversario. Infatti, se Alice \u00e8 in conflitto solo con Bob, accogliendo Alice tra i due, non perdiamo: Bob potrebbe avere altri conflitti, mentre Alice certamente non ne ha. Inoltre, \u00e8 del tutto senza senso non far entrare entrambe le parti. Dopo tali operazioni, non rimane pi\u00f9 di <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/36df7afd34e8b5cb15b525cadad4a825.png\" style=\"display:block;margin: 0 auto;\"> ospiti con una sorte irrisolta: in totale abbiamo <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/a84f12e5474d59b7836cfcc462850449.png\" style=\"display:block;margin: 0 auto;\"> conflitti, ciascuno con due partecipanti e ognuno partecipa ad almeno due. Dunque, rimane da soppesare solamente <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/1ed4854e1ddcfb0abc691abb7d3265fd.png\" style=\"display:block;margin: 0 auto;\"> opzioni, che potrebbe essere considerato come mezza giornata su un portatile.<\/p>\n<p>In realt\u00e0, con ragionamenti semplici si possono ottenere condizioni ancora pi\u00f9 favorevoli. Notiamo che dobbiamo necessariamente risolvere tutte le controversie, cio\u00e8 per ogni coppia in conflitto scegliere almeno una persona che non accoglieremo. Consideriamo il seguente algoritmo: prendiamo uno qualsiasi dei conflitti, rimuoviamo un partecipante e lanciamo ricorsivamente il processo dal resto, poi rimuoviamo l'altro e anche in questo caso lanciamo ricorsivamente. Poich\u00e9 ad ogni passo scartiamo qualcuno, l'albero della ricorsione di tale algoritmo \u00e8 un albero binario di profondit\u00e0 <i>k<\/i>, quindi complessivamente l'algoritmo funziona in <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/734c8d9f994b64e4f22de8bdee92ba7c.png\" style=\"display:block;margin: 0 auto;\">, dove <i>n<\/i> \u2014 numero di nodi, mentre <i>m<\/i> \u2014 numero di lati. Nel nostro esempio si tratta di circa dieci milioni, che possono essere calcolati in frazioni di secondo non solo su un portatile, ma anche su un telefono cellulare.<\/p>\n<p>L'esempio sopra riportato \u00e8 un esempio di <b>algoritmo parametrizzato.<\/b>Gli algoritmi parametrizzati sono algoritmi che funzionano in tempo <i>f(k) poly(n)<\/i>, dove <i>p<\/i> \u2014 polinomiale, <i>f<\/i> \u2014 una funzione calcolabile arbitraria, e <i>k<\/i> \u2014 un qualche parametro che, molto probabilmente, sar\u00e0 molto pi\u00f9 piccolo della dimensione del problema.<\/p>\n<p>Tutte le considerazioni precedenti a questo algoritmo portano all'esempio di <b>kernelizzazione.<\/b> \u2014 una delle tecniche comuni per la creazione di algoritmi parametrizzati. La kernelizzazione \u00e8 la riduzione della dimensione del problema a un valore limitato da una funzione del parametro. Il problema ottenuto \u00e8 spesso chiamato nucleo. Cos\u00ec, attraverso semplici ragionamenti sulle potenze delle vertici, abbiamo ottenuto un nucleo quadratico per il problema del Vertex Cover, parametricamente dimensionato sulla dimensione della risposta. Esistono altri parametri che si possono scegliere per questo problema (ad esempio, Vertex Cover Above LP), ma discuteremo proprio di questo parametro.<\/p>\n<h3>Pace Challenge<\/h3>\n<p>Competizione <noindex><a rel=\"nofollow\" href=\"https:\/\/pacechallenge.wordpress.com\">PACE Challenge<\/a><\/noindex> (The Parameterized Algorithms and Computational Experiments Challenge) \u00e8 nato nel 2015 per stabilire un legame tra gli algoritmi parametrizzati e gli approcci pratici utilizzati per risolvere problemi computazionali. Le prime tre competizioni erano dedicate alla ricerca della larghezza degli alberi di un grafo (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Treewidth\">Treewidth<\/a><\/noindex>), alla ricerca dell'albero di Steiner (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Steiner_tree_problem\">Steiner Tree<\/a><\/noindex>) e alla ricerca di un insieme di vertici che separa i cicli (<noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Feedback_vertex_set\">Feedback Vertex Set<\/a><\/noindex>). Quest'anno, una delle sfide in cui \u00e8 stato possibile mettersi alla prova era il problema di copertura dei vertici sopra descritto.<\/p>\n<p>La competizione cresce in popolarit\u00e0 di anno in anno. Se le informazioni preliminari sono corrette, quest'anno solo nella competizione per la risoluzione del problema di copertura dei vertici hanno partecipato 24 squadre. Vale la pena sottolineare che la competizione non dura solo alcune ore e neppure una settimana, ma diversi mesi. Le squadre hanno la possibilit\u00e0 di studiare la letteratura, ideare una propria idea originale e tentare di realizzarla. In sostanza, questa competizione rappresenta un lavoro di ricerca. Le idee delle soluzioni pi\u00f9 efficaci e la premiazione dei vincitori si svolgeranno in concomitanza con la conferenza <noindex><a rel=\"nofollow\" href=\"https:\/\/www.science-community.org\/en\/node\/202320\">IPEC<\/a><\/noindex> (International Symposium on Parameterized and Exact Computation) nell'ambito del pi\u00f9 grande incontro annuale di algoritmi in Europa <noindex><a rel=\"nofollow\" href=\"https:\/\/algo2019.ak.in.tum.de\">ALGO<\/a><\/noindex>. Maggiori informazioni sulla competizione stessa sono disponibili su <noindex><a rel=\"nofollow\" href=\"https:\/\/pacechallenge.org\/about\/\">sito<\/a><\/noindex>, mentre i risultati degli anni passati si trovano <noindex><a rel=\"nofollow\" href=\"https:\/\/pacechallenge.org\/past\/\">qui<\/a><\/noindex>.<\/p>\n<h3>Schema di soluzione<\/h3>\n<p>Per affrontare il problema della copertura dei vertici, ho provato ad applicare algoritmi parametrizzati. Questi di solito consistono in due parti: regole di semplificazione (che idealmente portano a una kernelizzazione) e regole di biforcazione. Le regole di semplificazione sono una pre-elaborazione dell'input in tempo polinomiale. L'obiettivo di queste regole \u00e8 ridurre il problema a un problema equivalente di dimensioni minori. Le regole di semplificazione sono la parte pi\u00f9 costosa dell'algoritmo e l'applicazione di questa parte porta a un tempo di esecuzione complessivo <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/42f72525b5bb21da5e2e81313bbc58e4.png\" style=\"display:block;margin: 0 auto;\"> invece di un semplice tempo polinomiale. Nel nostro caso, le regole di biforcazione si basano sul fatto che per ogni vertice bisogna scegliere di prendere in considerazione sia esso che il suo vicino.<\/p>\n<p>Lo schema generale \u00e8 il seguente: applichiamo le regole di semplificazione, poi scegliamo un vertice e facciamo due chiamate ricorsive: nella prima prendiamo il vertice in questione, mentre nell'altra consideriamo tutti i suoi vicini. Questo lo chiamiamo biforcarsi su questo vertice.<\/p>\n<p>A questo schema verr\u00e0 aggiunta esattamente un'aggiunta nel paragrafo successivo.<\/p>\n<h3>Idee per le regole di biforcazione<\/h3>\n<p>Discutiamo su come scegliere il vertice su cui avverr\u00e0 la biforcazione.<br \/>\nL'idea principale \u00e8 molto affamata dal punto di vista algoritmico: prendiamo il vertice di massimo grado e biforchiamo esattamente su di esso. Perch\u00e9 sembra migliore? Perch\u00e9 nel secondo ramo della chiamata ricorsiva elimineremo in questo modo molti vertici. Ci si pu\u00f2 aspettare che rimanga un grafo ridotto e su di esso lavoreremo rapidamente.<\/p>\n<p>Questo approccio, insieme alle semplici tecniche di kernelizzazione gi\u00e0 discusse, si presenta piuttosto bene, risolvendo alcuni test di dimensioni nell'ordine di alcune migliaia di vertici. Tuttavia, ad esempio, funziona male per i grafi cubici (cio\u00e8 grafi in cui il grado di ogni vertice \u00e8 tre).<br \/>\nC'\u00e8 un'altra idea, basata su una considerazione abbastanza semplice: se il grafo non \u00e8 connesso, il problema sui suoi componenti di connettivit\u00e0 pu\u00f2 essere risolto in modo indipendente, unendo le risposte alla fine. Questa, tra l'altro, \u00e8 la piccola modifica promessa nello schema, che accelerer\u00e0 notevolmente la soluzione: prima in questo caso lavoravamo per il prodotto dei tempi di conteggio delle risposte dei componenti, ora lavoriamo per la somma. E per accelerare la biforcazione \u00e8 necessario trasformare un grafo connesso in un grafo non connesso.<\/p>\n<p>Come fare? Se nel grafo c'\u00e8 un punto di giunzione, bisogna ramificare proprio in quel punto. Un punto di giunzione \u00e8 un vertice tale che, se rimosso, il grafo perde connettivit\u00e0. Trovare tutti i punti di giunzione in un grafo pu\u00f2 essere fatto con un algoritmo classico in tempo lineare. Questo approccio accelera notevolmente la ramificazione.<br \/>\n<img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/3818a0e69b169e464b9685133ebcc1c7.png\" style=\"display:block;margin: 0 auto;\"><br \/>\nRimuovendo uno qualsiasi dei vertici evidenziati, il grafo si frantumer\u00e0 in componenti connesse.<\/p>\n<p>Lo faremo, ma ci piacerebbe di pi\u00f9. Ad esempio, cercare nel grafo piccoli tagli di vertici e effettuare la ramificazione sui vertici estratti. Il modo pi\u00f9 efficiente che conosco per trovare il taglio globale minimo dei vertici \u00e8 utilizzare l'albero di Gomory-Hu, che si costruisce in tempo cubico. Nella PACE Challenge, la dimensione tipica del grafo \u00e8 di alcune migliaia di vertici. In tale situazione, in ogni vertice dell'albero di ricorsione bisogna eseguire miliardi di operazioni. Risultato: risolvere il problema nel tempo previsto \u00e8 praticamente impossibile.<\/p>\n<p>Proviamo a ottimizzare la soluzione. Un taglio minimo tra una coppia di vertici pu\u00f2 essere trovato utilizzando qualsiasi algoritmo che costruisce un flusso massimo. Possiamo applicare a tale rete <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0\">l'algoritmo di Dinic<\/a><\/noindex>, in pratica funziona molto velocemente. Ho il sospetto che teoricamente si possa dimostrare una stima sul tempo di esecuzione <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/db70377a9cf02b7fba4f72f422830f09.png\" style=\"display:block;margin: 0 auto;\">, che \u00e8 gi\u00e0 abbastanza accettabile.<\/p>\n<p>Ho provato diverse volte a cercare tagli tra coppie di vertici casuali e prendere il pi\u00f9 bilanciato. Sfortunatamente, nei test aperti della PACE Challenge ci\u00f2 ha portato a risultati deludenti. Ho confrontato con un algoritmo che si ramificava sui vertici di massimo grado, eseguendoli con un limite sulla profondit\u00e0 di discesa. Dopo l'algoritmo che cercava di trovare un taglio in questo modo, rimanevano grafi di dimensioni maggiori. Questo \u00e8 dovuto al fatto che i tagli risultavano molto sbilanciati: rimuovendo 5-10 vertici, si riusciva a staccarne solo 15-20.<\/p>\n<p>Va notato che negli articoli sui algoritmi teoricamente pi\u00f9 veloci si utilizzano tecniche di selezione dei vertici per la ramificazione molto pi\u00f9 avanzate. Queste tecniche hanno una realizzazione molto complessa e spesso scarse stime su tempo e memoria. Non sono riuscito a estrarne delle ragionevoli per la pratica.<\/p>\n<h3>Come applicare le regole di semplificazione<\/h3>\n<p>Abbiamo gi\u00e0 idee di kernelizzazione. Ricordo:<\/p>\n<ol>\n<li> Se c'\u00e8 un vertice isolato, rimuoverlo.<\/li>\n<li> Se c'\u00e8 un vertice di grado 1, rimuoverlo e prendere il suo vicino come risposta.<\/li>\n<li> Se c'\u00e8 un vertice di grado almeno <i>k + 1<\/i>, prenderlo come risposta.<\/li>\n<\/ol>\n<p>Con i primi due \u00e8 tutto chiaro, ma con il terzo c'\u00e8 un trucco. Se nel problema scherzoso del bar ci era stato dato un vincolo superiore su <i>k<\/i>, nel PACE Challenge bisogna semplicemente trovare una copertura del vertice di dimensione minima. Questa \u00e8 una tipica trasformazione degli problemi di ricerca (Search Problem) in problemi decisionali (Decision Problem), spesso tra questi due tipi di problemi non si fa differenza. In pratica, se scriviamo un risolutore per il problema della copertura del vertice, la differenza potrebbe esserci. Ad esempio, come nel terzo punto.<\/p>\n<p>Dal punto di vista dell'implementazione, ci sono due modi per procedere. Il primo approccio \u00e8 chiamato Iterative Deepening. Consiste nel seguente: possiamo iniziare con un ragionevole vincolo inferiore sulla risposta e poi avviare il nostro algoritmo utilizzando questo vincolo come vincolo superiore sulla risposta, senza scendere in ricorsione al di sotto di tale limitazione. Se troviamo una risposta, \u00e8 garantita come ottimale, altrimenti possiamo aumentare questo vincolo di uno e ripartire.<\/p>\n<p>Il secondo approccio consiste nel mantenere una qualche risposta ottimale attuale e cercare una risposta di dimensioni minori, modificando questo parametro al momento della scoperta <i>k<\/i> per una maggiore potatura di rami inutili nella ricerca.<\/p>\n<p>Dopo aver condotto diversi esperimenti notturni, mi sono orientato su una combinazione di questi due metodi: inizialmente avvio il mio algoritmo con un certo vincolo sulla profondit\u00e0 di ricerca (scegliendolo in modo che richieda un tempo trascurabile rispetto alla soluzione principale) e utilizzo la migliore soluzione trovata come vincolo superiore sulla risposta \u2014 cio\u00e8 su quel <i>k<\/i>.<\/p>\n<h3>Vertici di grado 2<\/h3>\n<p>Con i vertici di grado 0 e 1 ci siamo chiariti. Si scopre che si pu\u00f2 fare cos\u00ec anche con i vertici di grado 2, ma per questo, dal grafo, saranno necessarie operazioni pi\u00f9 complesse.<\/p>\n<p>Per spiegare questo, \u00e8 necessario in qualche modo denotare i vertici. Chiamiamo un vertice di grado 2 un vertice <i>v<\/i>, e i suoi vicini \u2014 vertici <i>x<\/i> e <i>y<\/i>. Successivamente avremo due casi.<\/p>\n<ol>\n<li>Quando <i>x<\/i> e <i>y<\/i> \u2014 vicini. Allora si pu\u00f2 prendere come risposta <i>x<\/i> e <i>y<\/i>, ma <i>v<\/i> rimuovere. Infatti, da questo triangolo, \u00e8 necessario prendere almeno due vertici come risposta e non perderemo sicuramente prendendo <i>x<\/i> e <i>y<\/i>: probabilmente hanno ancora vicini, mentre <i>v<\/i> loro non hanno.<\/li>\n<li>Quando <i>x<\/i> e <i>y<\/i> \u2014 non sono i vicini. Allora si afferma che tutti e tre i vertici possono essere uniti in uno. L'idea \u00e8 che in tal caso ci sia una risposta ottimale, in cui prenderemo o <i>v<\/i>, oppure entrambi i vertici <i>x<\/i> e <i>y<\/i>. Infatti, nel primo caso dovremo includere nella risposta tutti i vicini <i>x<\/i> e <i>y<\/i>, mentre nel secondo non \u00e8 necessario. Questo corrisponde esattamente ai casi in cui non includiamo il vertice unito nella risposta e quando lo facciamo. Resta solo da notare che in entrambi i casi la risposta a tale operazione diminuisce di uno.<\/li>\n<\/ol>\n<p><img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/92f40203ae094ce16be6576875addd66.png\" style=\"display:block;margin: 0 auto;\"><\/p>\n<p>\u00c8 importante notare che tale approccio \u00e8 piuttosto difficile da implementare correttamente in tempo lineare. L'unione dei vertici \u00e8 un'operazione complessa, \u00e8 necessario copiare le liste dei vicini. Se non si fa con attenzione, si pu\u00f2 ottenere un tempo di esecuzione asintoticamente non ottimale (ad esempio, se dopo ogni unione si copiano molti archi). Mi sono concentrato sulla ricerca di percorsi interi dai vertici di grado 2 e sull'analisi di molteplici casi speciali, come cicli formati da tali vertici o da tutti tranne uno di questi.<\/p>\n<p>Inoltre, \u00e8 necessario che questa operazione sia invertibile, in modo da poter ripristinare il grafo al suo stato originale durante il ritorno dalla ricorsione. Per garantire ci\u00f2, non ho svuotato le liste degli archi dei vertici uniti, dopo di che sapevo semplicemente quali archi dovevano essere diretti dove. Tale implementazione dei grafi richiede anche attenzione, ma garantisce un tempo lineare corretto. E per grafi con alcune decine di migliaia di archi, ci\u00f2 pone un'ottima compatibilit\u00e0 con la cache della CPU, il che conferisce grandi vantaggi in termini di velocit\u00e0.<\/p>\n<h3>Nucleo lineare<\/h3>\n<p>Infine, la parte pi\u00f9 interessante del nucleo.<\/p>\n<p>Iniziamo ricordando che nei grafi bipartiti \u00e8 possibile cercare il minimo copertura dei vertici in <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/ece1a2f10aa029a69351ae544746a310.png\" style=\"display:block;margin: 0 auto;\">. A tal fine \u00e8 necessario utilizzare l'algoritmo <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Hopcroft%E2%80%93Karp_algorithm\">Hopcroft-Karp<\/a><\/noindex> per trovare il massimo accoppiamento, e successivamente utilizzare il teorema <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/K%C5%91nig%27s_theorem_(graph_theory)\">di K\u00f6nig-Egervari.<\/a><\/noindex>.<\/p>\n<p>L'idea del nucleo lineare \u00e8 la seguente: prima dobbiamo bipartire il grafo, quindi al posto di ogni vertice <i>v<\/i> creiamo due vertici <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/366ed44646d5bab36a0ae19344aab430.png\" style=\"display:block;margin: 0 auto;\"> e <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/75a85ec774a083fb1901e466c26ab63b.png\" style=\"display:block;margin: 0 auto;\">, e invece di ogni arco <i>u \u2014 v<\/i> creiamo due archi <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/bde1ef08422cbfef5a002fb2f5330c53.png\" style=\"display:block;margin: 0 auto;\"> e <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/f70566a030c88b6d79787d46bff9ff47.png\" style=\"display:block;margin: 0 auto;\">Il grafo risultante sar\u00e0 bipartito. Troveremo in esso una copertura minima dei vertici. Alcuni vertici del grafo originale appariranno l\u00ec due volte, alcuni solo una volta, e alcuni non appariranno affatto. Il teorema di Nemhauser-Trotter afferma che in tal caso si possono rimuovere i vertici che non appaiono affatto e si possono includere nella risposta quelli che appaiono due volte. Inoltre, afferma che tra i vertici rimanenti (quelli che appaiono una sola volta) bisogna includere almeno la met\u00e0.<\/p>\n<p>Appena abbiamo imparato a lasciare nel grafo non pi\u00f9 di <i>2k<\/i> vertici. \u00c8 vero, se nella risposta rimanente c'\u00e8 almeno la met\u00e0 di tutti i vertici, allora il numero totale di vertici non sar\u00e0 maggiore di <i>2k<\/i>.<\/p>\n<p>Qui sono riuscito a fare un piccolo passo avanti. \u00c8 chiaro che il nucleo costruito in questo modo dipende da quale copertura minima dei vertici abbiamo utilizzato nel grafo bipartito. Vorrei scegliere quella che riduce al minimo il numero di vertici rimanenti. In passato, questo era possibile solo in un tempo di <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/065e2bde7ed31a306e1fbddaadae5440.png\" style=\"display:block;margin: 0 auto;\">. Ho per\u00f2 ideato un'implementazione di questo algoritmo in un tempo di <img decoding=\"async\" alt=\"Come risolvere problemi NP-difficili con algoritmi parametrizzati\" src=\"\/wp-content\/uploads\/2019\/06\/a12e9e03315fdfe4334364b4b8754119.png\" style=\"display:block;margin: 0 auto;\">, in questo modo, questo nucleo pu\u00f2 essere cercato in grafi di centinaia di migliaia di vertici ad ogni fase del branching.<\/p>\n<h3>Risultato<\/h3>\n<p>La pratica dimostra che la mia soluzione funziona bene su test con qualche centinaio di vertici e diverse migliaia di archi. Su tali test \u00e8 possibile aspettarsi che venga trovata una soluzione in mezz'ora. La probabilit\u00e0 di trovare una risposta in un tempo accettabile aumenta in linea di principio se nel grafo ci sono abbastanza vertici di alta grado, ad esempio grado 10 o superiore.<\/p>\n<p>Per partecipare alla competizione, le soluzioni dovevano essere inviate a <noindex><a rel=\"nofollow\" href=\"https:\/\/www.optil.io\/optilion\/\">optil.io<\/a><\/noindex>. A giudicare dalla tabella presentata l\u00ec <noindex><a rel=\"nofollow\" href=\"https:\/\/www.optil.io\/optilion\/problem\/3155?id=3155&amp;filename=main.cpp#tab-4\">, la mia soluzione occupa il terzo posto nei test aperti su venti, con un ampio distacco dal secondo. Se vogliamo essere completamente onesti, non \u00e8 del tutto chiaro come verranno valutate le soluzioni nella competizione vera e propria: ad esempio, la mia soluzione passa meno test rispetto a quella al quarto posto, ma su quelli che passa, funziona pi\u00f9 rapidamente.<\/a><\/noindex>I risultati dei test chiusi saranno resi noti il primo di luglio.<\/p>\n<p>Il lavoro di ricerca scientifica \u00e8, probabilmente, la parte pi\u00f9 interessante della nostra formazione. L'idea \u00e8 di provare, ancora all'universit\u00e0, a cimentarsi nella direzione scelta.<\/p>\n<p>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/hsespb\/blog\/456130\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041d\u0430\u0443\u0447\u043d\u043e-\u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430, \u043f\u043e\u0436\u0430\u043b\u0443\u0439, \u0441\u0430\u043c\u0430\u044f \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043d\u0430\u0448\u0435\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f. \u0418\u0434\u0435\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0435\u0449\u0451 \u0432 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0431\u044f \u0432 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u044b \u0441 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0439 Software Engineering \u0438 Machine Learning \u0447\u0430\u0441\u0442\u043e \u0438\u0434\u0443\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u041d\u0418\u0420\u044b \u0432 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 (\u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c, JetBrains \u0438\u043b\u0438 \u042f\u043d\u0434\u0435\u043a\u0441, \u043d\u043e \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e). \u0412 \u044d\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0441\u0432\u043e\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043f\u043e \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044e Computer Science. [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":26562,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[702],"tags":[],"class_list":["post-35406","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041d\u0430\u0443\u0447\u043d\u043e-\u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430, \u043f\u043e\u0436\u0430\u043b\u0443\u0439, \u0441\u0430\u043c\u0430\u044f \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043d\u0430\u0448\u0435\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f. \u0418\u0434\u0435\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0435\u0449\u0451 \u0432 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0431\u044f \u0432 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0438.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/it\/blog\/news\/kak-reshat-np-trudnye-zadachi-s-pomoshhyu-parametrizovannyh-algoritmov\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041a\u0430\u043a \u0440\u0435\u0448\u0430\u0442\u044c NP-\u0442\u0440\u0443\u0434\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041d\u0430\u0443\u0447\u043d\u043e-\u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430, \u043f\u043e\u0436\u0430\u043b\u0443\u0439, \u0441\u0430\u043c\u0430\u044f \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043d\u0430\u0448\u0435\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f. \u0418\u0434\u0435\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0435\u0449\u0451 \u0432 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0431\u044f \u0432 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0438.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/blog\/news\/kak-reshat-np-trudnye-zadachi-s-pomoshhyu-parametrizovannyh-algoritmov\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:04:08+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2021-01-02T11:01:41+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Come risolvere problemi NP-difficili con algoritmi parametrizzati | ProHoster","description":"\ud83e\udd47Come risolvere problemi NP-difficili con algoritmi parametrizzati | ProHoster","canonical_url":"https:\/\/prohoster.info\/it\/blog\/news\/kak-reshat-np-trudnye-zadachi-s-pomoshhyu-parametrizovannyh-algoritmov","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041a\u0430\u043a \u0440\u0435\u0448\u0430\u0442\u044c NP-\u0442\u0440\u0443\u0434\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432 | ProHoster","og:description":"\u041d\u0430\u0443\u0447\u043d\u043e-\u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430, \u043f\u043e\u0436\u0430\u043b\u0443\u0439, \u0441\u0430\u043c\u0430\u044f \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043d\u0430\u0448\u0435\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f. \u0418\u0434\u0435\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0435\u0449\u0451 \u0432 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0431\u044f \u0432 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0438.","og:url":"https:\/\/prohoster.info\/it\/blog\/news\/kak-reshat-np-trudnye-zadachi-s-pomoshhyu-parametrizovannyh-algoritmov","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:04:08+00:00","article:modified_time":"2021-01-02T11:01:41+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"35406","title":null,"description":"","keywords":"","keyphrases":null,"primary_term":null,"canonical_url":"","og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 23:06:35","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 02:03:22","updated":"2026-01-21 23:06:35","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/35406","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=35406"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/35406\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media\/26562"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=35406"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=35406"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=35406"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}