cs50 tideman (преобразование информации из одного массива в другой, более крупный)

#c #algorithm #logic #cs50 #array-algorithms

Вопрос:

Я завершил и представил более легкую версию задачи, поставленной на неделю, на которой я работаю, я просто заинтересован в завершении более сложной версии для обучения, но я застрял на том, что кажется сутью этого. В принципе, вы должны внедрить систему голосования, которая регистрирует все звания каждого из избирателей. Так, например, предположим, что у вас есть 3 кандидата (A, B и C). Если первый избиратель выберет кандидата C в качестве своего первого выбора, а A в качестве второго (B в качестве последнего), исходный массив, который у вас будет, будет выглядеть следующим образом [2,0,1], что означает, что третий кандидат является первым выбором, первый кандидат является вторым выбором, а второй кандидат является третьим выбором. Код, который я использовал для этого, выглядит следующим образом:

 bool vote(int rank, string name, int ranks[])
{
    for (int i = 0; i < candidate_count; i  )
    {
        if(strcmp(candidates[i], name) == 0)
        {
            ranks[rank] = i;

            for( int j = 0; j < candidate_count; j  )
            {
                printf("%in", ranks[j]);
            }
            return true;
        }
    }
    return false;
}
 

Но затем нас просят преобразовать его в 2d-массив, который сравнивает каждого из кандидатов в основном в битве 1 на 1. Таким образом, в нашем примере ABC массив должен преобразовываться из [2,0,1] в [[0,1,0],[0,0,0],[1,1,0]]
где первый массив представляет первого кандидата и как они действовали против 2-го и 3-го соответственно и т. Д. (первое место в первом массиве всегда должно быть 0, потому что вы не можете сравнить кандидата с тем, сколько голосов они имели против себя, то же самое со средним местом во втором массиве и последним местом в последнем массиве). Другими словами, массив[i][j] представляет, как кандидат i выступил против кандидата j. Вы должны разработать эту функцию, используя массив, возвращенный функцией голосования.

Я знаю, что это будет включать в себя еще один вложенный цикл, возможно, 3 слоя. Мне нужна точка в правильном направлении. Я сделал кучу различных настроек для функции, которая выглядит так, но я знаю, что все они были неправильными, потому что я прибегаю к методу проб и ошибок, а не к логике, потому что логика победила меня в этот момент. Возможно, этот форум на самом деле не предназначен для логической помощи, но я все равно хотел бы разобраться в этом самостоятельно, не получая ответа. В любом случае, вот последняя версия функции, с которой я беспомощно возился.

 void record_preferences(int ranks[])
{
    printf("n");

    for (int i = 0; i < candidate_count; i  )
    {
        for (int j = 0; j < candidate_count; j  )
        {
            for (int k = 0; k < candidate_count; k  )
            {
                if((ranks[k] > i amp;amp; ranks[k] < j) || (ranks[k] < i amp;amp; ranks[k] > j))
                {
                    preferences[i][j]  = 1;
                }
            }
            printf("%in", preferences[i][j]);
        }
    }
    return;
}
 

Имейте в виду, что я уже получил оценку за эту неделю, и я не планирую отправлять эту работу, так что это не обман, даже если вы прямо скажете мне ответ, но я бы предпочел, чтобы вы этого не делали. Я знаю, что многие люди считают, что вам нужно самому разобраться в логике, иначе вы на самом деле не учитесь, что я отчасти понимаю, но в то же время вы можете только много раз биться головой о стену, прежде чем обратиться за помощью.
Спасибо.

Изменить: вот ссылка на более четкое объяснение. Рассматриваемая функция начинается примерно в 7:30. https://www.youtube.com/watch?v=kb83NwyYI68amp;t=492samp;ab_channel=CS50

Комментарии:

1. Вам нужно заполнить массив 3×3, так что, по моему мнению, потребуется двойной массив. В вашем примере ранг {2,0,1} должен соответствовать {{0,1,0},{0,0,0},{1,1,0}} чего я не понимаю. Я получаю нулевую диагональ. Но я, должно быть, что-то упускаю. Если A является наименее любимым, почему предпочтение не {0, 0, 0}. Аналогично для B и C я ожидал бы { 1, 0, 1} и { 1, 0, 0}?

2. Для тех, кто читает в будущем: самый простой способ сделать это-учесть, что массив рангов показывает кандидатов в порядке от победителя до проигравшего. таким образом, предпочтения[ранг[i]] будут представлять позицию в массиве предпочтений, в которой находится победивший кандидат, а предпочтения[ранг[i][j]] будут представлять всех кандидатов, которых они победили (где i-количество кандидатов, а j-количество кандидатов после i).

Ответ №1:

Используя этот термин vote вместо ranks для согласованности с видео. Это также более понятно, поскольку нам также нужно иметь дело с формой множественного votes числа .

Решение немного длинновато, но ключевым моментом является функция rank() , которая возвращает позицию candidate для данного vote . Мы вызываем rank() для кандидата i и j и увеличиваем preferences[i][j] , если i ранг выше ( < ), чем j .

Введено enum candidates для удобства чтения (использовались имена кандидатов из видео только для 2-го тестового примера; прокомментируйте определение ВОПРОСА). Это также приведет к ошибке компиляции, если вы неправильно напишете имя кандидата.

Кодекс предполагает, что все кандидаты ранжированы. Это прямолинейно, чтобы разделить количество кандидатов и количество кандидатов, которые оцениваются.

 #include <stdio.h>
#define LEN(a) (sizeof(a) / sizeof(*a))

enum candidates {
    Alice,
    Bob,
    Charlie
};

void preferences_print(size_t candidates_len, unsigned preferences[candidates_len][candidates_len]) {
    for(size_t i = 0; i < candidates_len; i  ) {
        for(size_t j = 0; j < candidates_len; j  ) {
            printf("%u%s", preferences[i][j], j   1 < candidates_len ? ", " : "");
        }
        printf("n");
    }
}

unsigned rank(size_t candidates_len, unsigned vote[candidates_len], enum candidates candidate) {
    for(size_t i = 0; i < candidates_len; i  ) {
        if(vote[i] == candidate) return i;
    }
    printf("Error: skipping invalid cadidate %d", candidate);
    return 0;
}

void votes_to_preferences(size_t votes_len, size_t candidates_len, enum candidates votes[votes_len][candidates_len], unsigned preferences[candidates_len][candidates_len]) {
    for(size_t v = 0; v < votes_len; v  ) {
        for(size_t i = 0; i < candidates_len; i  ) {
            for(size_t j = 0; j < candidates_len; j  ) {
                preferences[i][j]  =
                    rank(candidates_len, votes[v], i) <
                    rank(candidates_len, votes[v], j);
            }
        }
    }
}

int main() {
    enum candidates votes[][3] = {
#define QUESTION
#ifdef QUESTION
        { Charlie, Alice, Bob },
#else // VIDEO
        { Alice, Charlie, Bob },
        { Alice, Charlie, Bob },
        { Charlie, Alice, Bob },
        { Bob, Alice, Charlie }
#endif
    };
    unsigned preferences[LEN(*votes)][LEN(*votes)] = { { 0 } };
    votes_to_preferences(LEN(votes), LEN(*votes), votes, preferences);
    preferences_print(LEN(*votes), preferences);
    return 0;
}
 

Комментарии:

1. Результат не должен отличаться, это означает, что это не сработало. Поскольку вторая строка представляет количество голосов, которые b получил против других кандидатов, и в примере b был последним выбором, поэтому во второй строке должны быть все нули. Но вы дали мне пищу для размышлений, сравнив ранги[i] с рангами[j], так что спасибо.

2. В вопросе, который вы сказали о [2, 0, 1] «Если первый избиратель выберет кандидата C в качестве своего первого выбора, а B в качестве второго (А в качестве последнего)», так что же это?

3. Извини, ты прав, я все испортил. Это должно быть c первым, a вторым, b последним. Вот ссылка на лучшее объяснение. с 7:30 они говорят об этой функции. Еще раз спасибо. Я отредактирую свой пост. youtube.com/watch?v=kb83NwyYI68amp;t=492samp;ab_channel=CS50

4. Не беспокойтесь. Я обновлю свой ответ после того, как вы уточните данные.