• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Zadanie z USACO i algorytm LCA

Object Storage Arubacloud
0 głosów
258 wizyt
pytanie zadane 8 kwietnia 2021 w Algorytmy przez wojtek_suchy Mądrala (6,880 p.)
edycja 8 kwietnia 2021 przez wojtek_suchy

Robię to zadanie: http://www.usaco.org/index.php?page=viewproblem2&cpid=968
Używam przygotowuje dane pod LCA, sprawdzam czy na ścieżce 2 wierzchołków do LCA jest szukany rodzaj. Niestety mój program przechodzi tylko jeden test, więc albo nie rozumiem treści zadania, albo mam jakieś błedy w kodzie. Wiadomość czy dany wierzochłek ma rodzaj "H" czy "G" trzymam w masce bitowej.
Mój program zwraca że na ścieżce wystąpił dany rodzaj pomimo tego że go nie ma. (przynajmniej w jednym z testów tak jest, niestety testy mają n = 1000 więc nie mam jak ich analizować)

#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define ull unsigned long long

const ll INF = 1e9 + 7, MAXN = 1e5 + 7, MAXLOG = 17;

vector<vector<int>> graph(MAXN), jumps(MAXN, vector<int>(MAXLOG)), milk(MAXN, vector<int>(MAXLOG));
vector<int> depht(MAXN);

void setIO(string s){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    if (s != "-"){
        freopen((s + ".in").c_str(), "r", stdin);
        freopen((s + ".out").c_str(), "w", stdout);
    }
}

void dfs(int p, int v){
    jumps[v][0] = p;
    depht[v] = depht[p] + 1;
    for (auto child : graph[v])
        if (child != p)
            dfs(v, child);
}

bool lca(int x, int y, int f){
    int found = 0;

    //zawsze x jest nizej
    if (depht[x] < depht[y])
        swap(x, y);

    //wyrownujemy poziomy
    for (int i = MAXLOG-1; i >= 0; i--){
        if (depht[x] - (1 << i) >= depht[y]){
            found |= milk[x][i];
            x = jumps[x][i];
        }
    }

    //wyrownujac poziomy trafilismy do tego samego wierzochlka
    if (x == y)
        // spotkalismy 2 lub szukany  lub dla bezpieczenstwa sprawdzam 
        return found == 3 || found == f || milk[x][0] == f;

    //idziemy synow LCA
    for (int i = MAXLOG-1; i >= 0; i--){
        if (jumps[x][i] != jumps[y][i]){
            found |= milk[x][i];
            x = jumps[x][i];
            found |= milk[y][i];
            y = jumps[y][i];
        }
    }

    return found == 3 || found == f || milk[x][1] == f; // ojciec moze miec szukany rodzaj
}

int main(){
    setIO("1");
    int n, m;
    cin >> n >> m;

    char breed;
    for (int i = 1; i <= n; i++){
        cin >> breed;
        milk[i][0] = (breed == 'H') ? 1 : 2;
    }

    int a, b;
    for (int i = 0; i < n-1; i++){
        cin >> a >> b;
        graph[a].push_back(b);
        graph[b].push_back(a);
    }

    dfs(1, 1);

    for (int j = 1; j < MAXLOG; j++){
        for (int i = 1; i <= n; i++){
            jumps[i][j] = jumps[jumps[i][j-1]][j-1];
            milk[i][j] = milk[i][j-1] | milk[milk[i][j-1]][j-1];
        }
    }

    for (int i = 0; i < m; i++){
        cin >> a >> b >> breed;
        int to_find = (breed == 'H') ? 1 : 2;
        cout << lca(a, b, to_find);
    }

    return 0;
}

PS. czy ktoś mógłby podesłać kod w Pythonie który generuje drzewo? (spójny graf o liczbie krawędzi o jeden mniejszych niż liczba wierzchołków bez cykli)

EDIT: Napisałem generator testów

from random import randint
from random import choice

def main():
    with open("test.in", "w") as file:
        n = 10
        m = 5
        file.write(str(n) + " " + str(m) + "\n")
        for i in range(n):
            file.write(choice("HG"))
        file.write("\n")
        for i in range(2, n+1):
            file.write(str(randint(1, i-1)) +  " " + str(i) + "\n")
        for i in range(m):
            file.write(str(randint(1, n)) + " " + str(randint(1, n)) + " " + choice("HG") + "\n")

main()

1 odpowiedź

+2 głosów
odpowiedź 9 kwietnia 2021 przez Whistleroosh Maniak (56,980 p.)
wybrane 9 kwietnia 2021 przez wojtek_suchy
 
Najlepsza

Trochę mi to zajęło, ale naprawiłem ten kod. Tak wygląda po zmianach:

#include <bits/stdc++.h>
 
using namespace std;
 
#define ll long long
#define ull unsigned long long
 
const ll INF = 1e9 + 7, MAXN = 1e5 + 7, MAXLOG = 18;
 
vector<vector<int>> graph(MAXN), jumps(MAXN, vector<int>(MAXLOG)), milk(MAXN, vector<int>(MAXLOG));
vector<int> depht(MAXN);

int milk_node[MAXN];
 
void setIO(string s){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    if (s != "-"){
        freopen((s + ".in").c_str(), "r", stdin);
        freopen((s + ".out").c_str(), "w", stdout);
    }
}
 
void dfs(int p, int v){
    jumps[v][0] = p;
    milk[v][0] = milk_node[p] | milk_node[v];
    depht[v] = depht[p] + 1;
    for (auto child : graph[v])
        if (child != p)
            dfs(v, child);
}
 
bool lca(int x, int y, int f){
    int found = 0;

    if(x == y)
        return (milk_node[x] & f);
 
    //zawsze x jest nizej
    if (depht[x] < depht[y])
        swap(x, y);
 
    //wyrownujemy poziomy
    for (int i = MAXLOG-1; i >= 0; i--){
        if (depht[jumps[x][i]] >= depht[y]){
            found |= milk[x][i];
            x = jumps[x][i];
        }
    }

    if(x == y)
        return (found & f);

    //idziemy synow LCA
    for (int i = MAXLOG-1; i >= 0; i--){
        if (jumps[x][i] != jumps[y][i]){
            found |= milk[x][i];
            x = jumps[x][i];
            found |= milk[y][i];
            y = jumps[y][i];
        }
    }
    
    found |= milk[x][0];
    found |= milk[y][0];

    return (found & f);
}
 
int main(){
    setIO("milkvisits");
    int n, m;
    cin >> n >> m;
 
    char breed;
    for (int i = 1; i <= n; i++){
        cin >> breed;
        milk_node[i] = (breed == 'H') ? 1 : 2;
    }
 
    int a, b;
    for (int i = 0; i < n-1; i++){
        cin >> a >> b;
        graph[a].push_back(b);
        graph[b].push_back(a);
    }
 
    dfs(1, 1);
 
    for (int j = 1; j < MAXLOG; j++){
        for (int i = 1; i <= n; i++){
            jumps[i][j] = jumps[jumps[i][j-1]][j-1];
            milk[i][j] = milk[i][j-1] | milk[jumps[i][j-1]][j-1];
        }
    }
 
    for (int i = 0; i < m; i++){
        cin >> a >> b >> breed;
        int to_find = (breed == 'H') ? 1 : 2;
        cout << lca(a, b, to_find);
    }
 
    return 0;
}

Taki największy błąd to było to, że w linii 86 (w Twoim kodzie) wybierałeś zły indeks. Ponadto milk[x][0] zawiera informacje o wierzchołku x, a jump[x][0] skacze do przodka x. Lepiej będzie jeżeli i milk[x][0], i jump[x][0] wskazują na przodka x, bo wtedy łatwiej napisać pozostałe przejścia. Dlatego dodałem zmienną milk_node[x], która trzyma rodzaj mleka dla danego wierzchołka

komentarz 9 kwietnia 2021 przez wojtek_suchy Mądrala (6,880 p.)

ale ja jestem głupi xDDD

 milk[milk[i][j-1]][j-1];

No tak napewno rodzaj mleka będzie odpowiednim indeksem xD


Ale jak dałeś że milk[i][0] przechowuje wartość wierzchołka i poprzednika i y będzie LCA x, to czy wtedy nie będziesz brał też pod uwagę poprzednika y który nie jest na ścieżce?

 

komentarz 9 kwietnia 2021 przez Whistleroosh Maniak (56,980 p.)
Linijka 51 powinna temu zaradzić. Bo jeżeli x jest potomkiem y, to wtedy found zawiera wszystkie wierzchołki od x do y włącznie

Podobne pytania

+1 głos
1 odpowiedź 93 wizyt
pytanie zadane 29 marca w C i C++ przez Dani Obywatel (1,450 p.)
0 głosów
1 odpowiedź 425 wizyt
0 głosów
0 odpowiedzi 938 wizyt
pytanie zadane 4 stycznia 2018 w Algorytmy przez Ola Paczyńska Nowicjusz (120 p.)

92,554 zapytań

141,399 odpowiedzi

319,535 komentarzy

61,938 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...