C++ 排名选择投票

C++ 排名选择投票,c++,C++,我目前正在编写一个程序,它根据一个包含3次测试选举的输入文本文件执行一系列的排名选择选举,每个测试选举有3名候选人中的5张选票。然后输出每次选举的获胜候选人 问题是,对于第一次测试选举,获胜者的输出显示为候选人-1获胜。假设是,候选人2获胜。基于第一次测试选举的结果 我尝试在int main之前将返回值从“-1”更改为“2”。它确实输出了我想要的东西,但我正在努力避免硬编码。如果有人能给我提示如何以其他方式解决这个问题,我将不胜感激 Text Fileelections.txt: 15 1 2

我目前正在编写一个程序,它根据一个包含3次测试选举的输入文本文件执行一系列的排名选择选举,每个测试选举有3名候选人中的5张选票。然后输出每次选举的获胜候选人

问题是,对于第一次测试选举,获胜者的输出显示为候选人-1获胜。假设是,候选人2获胜。基于第一次测试选举的结果

我尝试在int main之前将返回值从“-1”更改为“2”。它确实输出了我想要的东西,但我正在努力避免硬编码。如果有人能给我提示如何以其他方式解决这个问题,我将不胜感激

Text Fileelections.txt:

15
1
2
3
3
2
1
2
1
3
1
2
3
2
3
1
15
1
2
3
1
2
3
1
2
3
1
2
3
2
1
3
15
3
2
1
3
2
1
3
1
2
1
2
3
1
3
2
我的代码:

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <iomanip>
using namespace std;

const char *FILENAME = "elections.txt";
const int MAXBALLOTS = 500;
const int NUM_CANDIDATES = 3;

int elect_candidate(int ballots[MAXBALLOTS][NUM_CANDIDATES],
                    int numBallots) {

        int tally[NUM_CANDIDATES + 1] = { 0 };
        double percentages[NUM_CANDIDATES + 1];

        for (int i = 0; i < numBallots; i++) {

        int j;
        for (j = 0; j < NUM_CANDIDATES; ++j) {
        if (ballots[i][j] > 0)
            break;
        }
        if (j < NUM_CANDIDATES) {
        int choice = ballots[i][j];
        tally[choice]++;
        }
    }
        int best = 1;
        int bestCount = 0;
        int worst = 1;
        cout << "Percentages for each candidate: " << endl;
        for (int i = 1; i < NUM_CANDIDATES + 1; i++) {
            percentages[i] = (double)tally[i] / numBallots;
            cout << fixed << setprecision(2);
            cout << "#" << i << ": " << percentages[i];
            cout << endl;

        if (tally[i] > tally[best]) {
        best = i;
        bestCount = 1;
        } else if (tally[i] == tally[best]) {
        ++bestCount;
        } else if (tally[i] < tally[worst]) {
        worst = i;
        }
    }
    if (best == worst) {
        return 0;
    }
    if (2 * tally[best] > numBallots) {
        return best;
    } else {
        for (int i = 0; i < numBallots; i++) {
        for (int j = 0; j < NUM_CANDIDATES; ++j) {
            if (tally[ballots[i][j]] == tally[worst]) {
            ballots[i][j] = 0;
            }
        }
    }
}
    return -1;
}
int main()
{
    ifstream f(FILENAME);
    string tmp;
    int nLines;
    int numBallots = 0;

    int ballots[MAXBALLOTS][NUM_CANDIDATES];

    cout << "********************" << endl;
    cout << "C++ Election of 2020" << endl;
    cout << "********************" << endl;

    // While we are not at end-of-file
    while (getline(f, tmp)) {
        // Read the number of lines for this election
        nLines = atoi(tmp.c_str());
        // Read in each ballot
        for (int i = 0; i < nLines; i += 3) {
            // Read in a single ballot (3 lines each)
            cout << "Read ballot: ";
            for (int j = 0; j < NUM_CANDIDATES; j++) {
                getline(f, tmp);
                ballots[numBallots][j] = atoi(tmp.c_str());
                cout << " " << ballots[numBallots][j];
            }
            numBallots++;
            cout << endl;
        }
        cout << "Read " << numBallots << " ballots..." << endl;
        cout << endl;

        int winner = -1;

        // Run the election
        winner = elect_candidate(ballots, numBallots);
        cout << "********************" << endl;
        cout << "Candidate #" << winner << " wins." << endl;
        cout << "********************" << endl;
        cout << endl;

        numBallots = 0;
    }
    return 0;
}
预期产出:

********************
C++ Election of 2020
********************
Read ballot:  1 2 3
Read ballot:  3 2 1
Read ballot:  2 1 3
Read ballot:  1 2 3
Read ballot:  2 3 1
Read 5 ballots...

Percentages for each candidate:
#1: 0.40
#2: 0.40
#3: 0.20
********************
Candidate #2 wins.
********************

Read ballot:  1 2 3
Read ballot:  1 2 3
Read ballot:  1 2 3
Read ballot:  1 2 3
Read ballot:  2 1 3
Read 5 ballots...

Percentages for each candidate:
#1: 0.80
#2: 0.20
#3: 0.00
********************
Candidate #1 wins.
********************

Read ballot:  3 2 1
Read ballot:  3 2 1
Read ballot:  3 1 2
Read ballot:  1 2 3
Read ballot:  1 3 2
Read 5 ballots...

Percentages for each candidate:
#1: 0.40
#2: 0.00
#3: 0.60
********************
Candidate #3 wins.
********************

在“当选候选人”的结尾,你有一个else语句,它做了一大堆无用的工作,因为你做了之后从来没有使用过它。你应该在另一个身体里决定一个胜利者,然后把它还给他。由于您没有这样做,函数末尾的return-1将被执行。

这看起来像是一个学习练习,您需要自己解决,我有一个不为这些编写代码的策略

然而,如果我能提出一个建议的话:试着把每一张选票代表为一组候选人,按偏好的递增顺序存储,也就是说,最后一个选择,下一个选择,…,第二个选择,第一个选择。然后将选票存储在一个数据库中,该数据库的键是当前每张选票所选的候选人。编辑:std::无序的_多重映射更好。您可以插入拥有选票数据的对象,或者只是移动向量,并为自己节省额外的间接层次。例如:

using Candidate = int;
// A ranking of candidates in order of last-place to first-place:
using Ballot = std::vector<Candidate>;
// A collection of ballots, each keyed to the highest-ranking candidates
// on the ballot who is still alive:
using BallotBox = std::unordered_multimap< Candidate, Ballot >;
一些测试用例。末尾的换行不是可选的

# Test data for rankedchoice.cpp
# Expected output: 4
8
1 4 3 2
2 4 3 1
2 1 4 3
3 1 2 4
3 2 1 4
3 1 4 2
4 2 3 1
4 1 3 4

# Expected output: 4
8
4 1 3 4
4 2 3 1
3 2 1 4
3 1 2 4
2 4 3 1
2 1 4 3
1 4 3 2
3 1 4 2

# Expected output: 1
1
1 2

# Expected output: 1
1
1

# Expected output: 2
3
1 2
2 1
2

# Expected output: 1 2
2
1 2
2 1

# Expected output: 1 3
6
1 2
1 3
1
3 2
3 1
2 3

# Expected output: 1
# Because there are no first-place votes for 4, it should be eliminated,
# and the 3 4 1 2 ballots should put 1 over the top on the second ballot.
9
1 2 3 4
1 2 3 4
1 2 3 4
2 1 3 4
2 4 1 3
2 4 1 4
2 4 1 3
3 4 1 2
3 4 1 2

# Expected Output: 3
5
1 2 3
2 1 3
3 1 2
3 2 1
3

# Expected Output: 3
5
1 2 3
1 3 2
2 3 1
3 1 2
3 2 1

你试过使用调试器了吗?顺便说一句,你应该做更多的分而治之。识别代码中可以命名的部分,并使它们成为某个类的函数或方法。如果这样做,在每次调用其中一个部分后,您可以通过调试器或打印查看当前变量并进行验证,找出哪个部分工作错误。
// This program requires C++17 or higher.

/* For the purposes of this exercise, data is read from standard input.
 * Data consists of zero or more election tallies, terminated by newlines.
 * The input encoding is UTF-8.  Lines beginning with # are comments, and
 * ignored.  Parsing and input-checking are minimal.
 *
 * Each election tally consists of:
 * - One line consisting of the number of ballots, N
 * - N ballots, each on its own line, consisting of space-separated integers,
 *   each identifying a candidate.  Higher-ranked candidates appear before
 *   lower-ranked ones on each ballot, no candidate may appear more than
 *   once on the same ballot, and a candidate must be the first choice of at
 *   least one voter to win.
 *
 * The expected output is, for each election tally:
 * The ID of the inning candidates (or a space-separated list of all candid=
 * ates tied for first place) followed by a newline.
 *
 * If more than one candidate is tied for last place, which last-place can-
 * didate is eliminated is arbitrary.  This could lead to an ambifuous result.
 * The algorithm doesn’t do tiebreakers (such as most first-place votes).
 */

#include <algorithm>
#include <array>
#include <assert.h>
#include <iostream>
#include <limits>
#include <memory>
#include <stdexcept>
#include <stdlib.h>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

using std::cerr;
using std::cin;
using std::cout;
using std::endl;

using Candidate = int;
// A ranking of candidates in order of last-place to first-place:
using Ballot = std::vector<Candidate>;
// A collection of ballots, each keyed to the highest-ranking candidates
// on the ballot who is still alive:
using BallotBox = std::unordered_multimap< Candidate, Ballot >;
using CandidateSet = std::unordered_set<Candidate>;

// Magic constant to make turn off lenght-checking:
constexpr auto huge_size = std::numeric_limits<std::streamsize>::max();

template <class It>
  std::ostream& print_list( std::ostream& out,
                            const It& begin,
                            const It& end )
/* Prints the elements in range to the provided stream, separated by spaces.
 * The type It must be a forward iterator.  Utility function intended to be
 * called by operator<< overloads.
 */
{
  if (begin != end) {
    out << *begin;

    It it = begin;
    ++it;

    while ( it != end )
      out << ' ' << *it++;
  }

  return out;
}

inline std::ostream& operator<<( std::ostream& out, const CandidateSet& x )
{
  return print_list( out, x.cbegin(), x.cend() );
}

inline std::ostream& operator<<( std::ostream& out, const Ballot& x )
{
  return print_list( out, x.cbegin(), x.cend() );
}

CandidateSet get_unique_keys( const BallotBox& x ) noexcept
/* Generates the set of keys in x.
 */
{
  CandidateSet results;

  if (!x.empty()) {
    auto it = x.cbegin();
    const Candidate* previous = &it->first;
    results.emplace(*previous);
    ++it;

    while (it != x.cend()) {
      if (it->first != *previous) {
        previous = &it->first;
        results.emplace(*previous);
      }
      ++it;
    } // end while
  } // end if

  return results; // Guaranteed copy elision.
}

BallotBox collect_ballots( std::istream& in = cin )
/* Creates the first round of the next election in the input stream, or
 * else throws a std::runtime_error.
 */
{
  unsigned n_votes;

  in >> n_votes;

  if (!in)
    throw std::runtime_error("Expected: number of votes.");

  if ( in.peek() == '\n' )
    in.get();
  else
    throw std::runtime_error("Expected: newline.");

  BallotBox ballot_box;
  ballot_box.reserve(n_votes);

  while (n_votes--) {
    while( in.peek() == '#' )
      in.ignore( huge_size, '\n');

    Ballot ballot;
    do {
      Candidate c;
      in >> c;

      if (!in)
        throw std::runtime_error("Expected: Candidate ID.");

      ballot.push_back(c);
    } while ( in.get() == ' ' );
    // The above never checks which non-space character it consumed, but it
    // should have been a newline.

    // For convenience, we inserted elements in the reverse order that our
    // algorithm needs.  Reversing is faster than front-insertions.
    std::reverse( ballot.begin(), ballot.end() );

    // Now we need to insert a node keyed to the first choice into the
    // BallotBox (multimap).
    const Candidate kodos = ballot.back();
    ballot_box.emplace( kodos, std::move(ballot) );
  }

  while (in && !in.eof() && in.peek() == '\n')
    in.get(); // Chomp trailing newlines.

  return ballot_box; // Guaranteed copy elision.
}

CandidateSet count_ballots( BallotBox&& ballot_box )
/* Consumes the initial state of the election and returns the Results of the
 * election.
 */
{
  using Tally = BallotBox::size_type;
  constexpr Tally votes_for_Stalin =
    std::numeric_limits<Tally>::max();
  constexpr Candidate noman = -1;

  CandidateSet candidates = get_unique_keys(ballot_box);
  Tally most_votes = 0;
  Tally fewest_votes = votes_for_Stalin;
  Candidate loser = noman;
  Candidate winner = noman;

  for ( const Candidate i : candidates ) {
    const Tally votes = ballot_box.count(i);

    if (votes > most_votes) {
      most_votes = votes;
      winner = i;
    }

    if (votes < fewest_votes) {
      fewest_votes = votes;
      loser = i;
    }
  } // end for

  while ( most_votes < (ballot_box.size()/2U + 1U) &&
          most_votes > fewest_votes &&
          !candidates.empty() && 
          !ballot_box.empty() ) {

    std::vector<Ballot> changed_votes;
    changed_votes.reserve(fewest_votes);
    candidates.erase(loser);

    while ( auto handle = ballot_box.extract(loser) ) {
      Ballot& ballot = handle.mapped();

      do {
        ballot.pop_back();
      } while ( candidates.find(ballot.back()) == candidates.end() );

     if (!ballot.empty()) {
        changed_votes.emplace_back(std::move(ballot));
      }
    } // end while

    for ( Ballot& b : changed_votes ) {
      assert(!b.empty());
      const Candidate new_key = b.back();
      ballot_box.emplace( std::move(new_key), std::move(b) );
    }

    most_votes = 0;
    fewest_votes = votes_for_Stalin;
    loser = noman;
    winner = noman;

    for ( const Candidate i : candidates ) {
      const auto votes = ballot_box.count(i);

      if (votes > most_votes) {
        most_votes = votes;
        winner = i;
      }

      if (votes < fewest_votes) {
        fewest_votes = votes;
        loser = i;
      } // end if
    } // end for
  } // end while

  if ( most_votes > fewest_votes ) {
   /* If this branch is reached, the while loop did not fail because all the
    * remaining candidates were tied: one candidate got more votes than
    * another.  Nor did it terminate because either the set of remaining can-
    * didates or the container of votes were empty.  Therefore, the loop
    * terminated for the only other possible reason: one candidate has won
    * a majority.
    */
    candidates.clear();
    candidates.insert(winner);
  }

  return candidates; // Guaranteed copy elision.
}

int main()
{
  try {
    while( cin && !cin.eof() ) {
      const auto next = cin.peek();

      if ( next == '#' || next == '\n' )
        cin.ignore( huge_size, '\n');
      else {
        cout << count_ballots(collect_ballots()) << endl;
      } // end if
    } // end while

    if (cin.fail())
      throw std::runtime_error("Failed to read from standard input.");

  } catch (const std::runtime_error& e) {
     cout.flush();
     cerr << "Error: " << e.what() << '\n';
     exit(EXIT_FAILURE);
  }

  return EXIT_SUCCESS;
}
# Test data for rankedchoice.cpp
# Expected output: 4
8
1 4 3 2
2 4 3 1
2 1 4 3
3 1 2 4
3 2 1 4
3 1 4 2
4 2 3 1
4 1 3 4

# Expected output: 4
8
4 1 3 4
4 2 3 1
3 2 1 4
3 1 2 4
2 4 3 1
2 1 4 3
1 4 3 2
3 1 4 2

# Expected output: 1
1
1 2

# Expected output: 1
1
1

# Expected output: 2
3
1 2
2 1
2

# Expected output: 1 2
2
1 2
2 1

# Expected output: 1 3
6
1 2
1 3
1
3 2
3 1
2 3

# Expected output: 1
# Because there are no first-place votes for 4, it should be eliminated,
# and the 3 4 1 2 ballots should put 1 over the top on the second ballot.
9
1 2 3 4
1 2 3 4
1 2 3 4
2 1 3 4
2 4 1 3
2 4 1 4
2 4 1 3
3 4 1 2
3 4 1 2

# Expected Output: 3
5
1 2 3
2 1 3
3 1 2
3 2 1
3

# Expected Output: 3
5
1 2 3
1 3 2
2 3 1
3 1 2
3 2 1