>> 문제 8. 호주식
투표법(Australian Voting)
PC/UVa ID: 110108/10142, 인기도: B, 성공률: 낮음, 레벨: 1
>> 문제
호주식 투표 제도에서는 투표권자가 모든 후보에 대해 선호도 순으로 순위를 매긴다. 처음에는 1순위로 선택한 것만 집계하며 한 후보가 50% 초과 득표하면 그 후보가 바로 선출된다. 하지만 50% 초과 득표한 후보가 없으면 가장 적은 표를 받은 후보(둘 이상이
될 수도 있음)가 우선 탈락된다. 그리고 이렇게 탈락된 후보를 1순위로 찍었던 표만 다시 집계하여 아직 탈락되지 않은 후보들 가운데 가장 높은 선호도를 얻은 후보가 그 표를
얻는다. 이런 식으로 가장 약한 후보들을 탈락시키면서 그 다음 순위의 아직 탈락하지 않은 후보에게 표를
주는 과정을 50%가 넘는 표를 얻는 후보가 나오거나 탈락되지 않은 모든 후보가 동률이 될 때까지 반복한다.
>> 입력
입력 케이스의 개수를 나타내는 양의 정수 한 개가 들어있는 행으로 시작되며 그 줄에는 그 숫자밖에 입력되지 않는다. 그 뒤에는 빈 줄이 하나 들어가고 서로 다른 입력 케이스 사이에는 두 개의 빈 줄이 입력된다. 각 케이스의 첫번째 줄에는 후보 수를 나타내는 20이하의 정수 n이 입력된다. 그 밑으로 n개의
줄에 걸쳐서 후보의 이름이 순서대로 입력되며 각 후보의 이름을 80글자 이하로, 출력 가능한 문자로 구성된다. 그 뒤에는 최대 1,000줄이 입력될 수 있는데, 각 줄에는 투표 내역이 입력된다. 각 투표 내역에는 어떤 순서로 1 부터 n까지의 수가 입력된다. 첫번째 숫자는 1순위로 찍은 후보의 번호, 두번째 숫자는 2순위로 찍은 후보의 번호, 이런식으로 숫자가 기록된다.
>> 출력
각 테스트 게이스에 대해 당선된 후보의 이름 한줄, 또는 동률을 이룬
후보들의 이름이 들어있는 여러줄을 출력한다. 두 개 이상의 테스트 케이스가 있을 경우 각 결과는 한
개의 빈 줄로 구분한다.
>> 입력예
1
3
John Doe
Jane Smith
Sirhan Sirhan
1 2 3
2 1 3
2 3 1
1 2 3
3 1 2
|
>> 출력 예
John Doe
|
main.cpp
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
#define BALLOT vector<int>
#define BALLOT_BOX vector<BALLOT>
class Candidate{
// 후보자 클래스.
public:
Candidate(){}
Candidate(const int & pIndex, const string & pName)
{
this->name = pName;
this->index = pIndex;
this->share = 0.0;
}
~Candidate(){
// 투표함 폐기.
BALLOT_BOX ::iterator it;
for(it = this->ballotbox.begin(); it != this->ballotbox.end(); it++)
(*it).erase((*it).begin(), (*it).end());
this->ballotbox.erase(this->ballotbox.begin(), this->ballotbox.end());
}
string name;
int index;
// 투표즉시 후보자의 투표함에 넣어 계산을 쉽게하자.
BALLOT_BOX ballotbox;
double share;
};
#define CANDIDATES vector<Candidate*>
class PollingPlace
{
public:
PollingPlace(){}
~PollingPlace(){}
private:
typedef struct tag_progress{
// 진행정보 구조체.
typedef enum tagStatus{
_BEGIN_ = 0,
_BEFOR_CANDIDACY_,
_CANDIDACY_,
_VOTE_,
_END_,
}STATUS;
private:
STATUS status;
public:
int totalTestCase; // 해야할 투표들
int nowTestCase; // 진행된 투표들
int totalCandidates;// 입후보할 후보수
int nowCandidates; // 입후보한 후보수
int voteCount; // 투표수
bool ballotCount; // 개표 유무
tag_progress() {
nowCandidates = totalCandidates = 0;
nowTestCase = totalTestCase = 0;
voteCount = 0;
ballotCount = false;
status = tag_progress::_BEGIN_;
}
STATUS NowStatus(void) {
// 리턴값에 따라 프로그램 진행이 달라짐.
return status;
}
// 다음 진행상태로 변환한다.
void NextStatus(void) {
if ( status == _BEGIN_ && totalTestCase > 0)
status = _BEFOR_CANDIDACY_;
else if ( status == _BEFOR_CANDIDACY_ && totalCandidates > 0)
status = _CANDIDACY_;
else if ( status == _CANDIDACY_ && totalCandidates == nowCandidates)
status = _VOTE_;
else if ( status == _VOTE_ && ballotCount == true)
{
if ( ++nowTestCase < totalTestCase )
{
status = _BEFOR_CANDIDACY_;
nowCandidates = totalCandidates = 0;
}
else
status = _END_;
ballotCount = false;
voteCount = 0;
}
else if ( status == _VOTE_ && ballotCount == false)
++voteCount;
}
}PROGRESS;
#define PRG tag_progress
PROGRESS progress;
CANDIDATES candidates;
public:
bool CmdLine(const string& line)
{
bool ret = true;
switch(progress.NowStatus())
{
case PRG::_BEGIN_:
this->SetTestCase(line); // 테스트 셋팅
break;
case PRG::_BEFOR_CANDIDACY_:
this->SetCandidates(line); // 입후보 셋팅
break;
case PRG::_CANDIDACY_:
this->Candidacy(line); // 입후보
break;
case PRG::_VOTE_:
if ( line.length() > 0 && // 문자열이 있으면
this->progress.voteCount <= 1000 )
this->Vote(line); // - 투표
else // 없으면
this->VoteCount(); // - 개표
break;
case PRG::_END_:
ret = false; // 종료
break;
}
return ret;
}
private:
void SetTestCase(const string & cmd)
{
this->progress.totalTestCase = atoi(cmd.c_str());
cout << endl;
this->progress.NextStatus();
}
void SetCandidates(const string & cmd)
{
this->progress.totalCandidates = atoi(cmd.c_str());
this->progress.NextStatus();
}
void Candidacy(const string & pName)
{
int len = pName.size();
if (len > 0 && len <= 80)
{
this->candidates.push_back(new Candidate(this->candidates.size()+1, pName));
++this->progress.nowCandidates;
this->progress.NextStatus();
}
}
void Vote(const string & cmd)
{
string buf;
stringstream ss(cmd);
vector<string> tokens;
while ( ss >> buf )
tokens.push_back(buf);
// 투표가 제대로 된거라면.
if ( tokens.size() == this->progress.totalCandidates )
{
// 무효표 검사.
bool undervote = false;
for(unsigned int i = 0; i < tokens.size(); i++)
{
int temp = atoi(tokens[i].c_str());
if ( temp < 1 || temp > this->progress.totalCandidates)
undervote = true;
}
if ( undervote == false)
{
BALLOT dummyBallot;
// 투표용지를 만들고
for(unsigned int i = 0; i < tokens.size(); i++)
dummyBallot.push_back(atoi(tokens[i].c_str()));
// 선호도가 1순위에 있는 사람 투표함에 바로 넣는다.
int preference = atoi(tokens[0].c_str())-1;
this->candidates[preference]->ballotbox.push_back(dummyBallot);
}
}
// 무효표도 투표는 한거다.
this->progress.NextStatus();
}
void VoteCount(void)
{
bool election = false;
// 당선자를 찾을때까지 반복.
while(election==false)
{
// 후보자들의 선호도를 계산한다.
CANDIDATES ::iterator it;
for(it = this->candidates.begin(); it != this->candidates.end(); it++)
if ( this->progress.voteCount > 0 ) // 0을 나눌수 없다.
(*it)->share = (double)(*it)->ballotbox.size()/(double)this->progress.voteCount*100.0;
// 혹시 모를 모두다 동률이면
double sami = (*this->candidates.begin())->share;
bool samiflag = true;
for(it = this->candidates.begin(); it != this->candidates.end(); it++)
if ( (*it)->share != sami ) samiflag = false;
if ( samiflag == true )
{
// 동률이면 그냥 이름 다 출력하고 나감.
for(it = this->candidates.begin(); it != this->candidates.end(); it++)
cout << (*it)->name << endl;
cout << endl;
election = true;
break;
}
// 50% 이상인 후보자를 찾고.
for(it = this->candidates.begin(); it != this->candidates.end(); it++) {
if( (*it)->share >= 50.0 )
{
election = true;
break;
}
}
// 50% 당선자가
if ( election == true )
{
// 있으면 당선.
cout << (*it)->name << endl << endl;
}
else
{
// 없으면, 최저율인 사람을 제거. 투표함을 넘김.
this->TransBalllt();
}
}
this->Release();
this->progress.ballotCount = true; // 개표끝.
this->progress.NextStatus();
}
void TransBalllt(void)
{
// 최소값을 구할것이기 때문에 초기값은 최대값.
double minShare = 100.0;
CANDIDATES ::iterator it;
for(it = this->candidates.begin(); it != this->candidates.end(); it++)
minShare = min(minShare, (*it)->share);
for(it = this->candidates.begin(); it != this->candidates.end(); it++)
{
Candidate* Dummy = (*it);
if ( minShare == Dummy->share ) // 최저율인 사람의
{
// 투표함을 뒤지면서 다음 후보자에게 분배한다.
BALLOT_BOX ::iterator ballotit;
for( ballotit = Dummy->ballotbox.begin(); ballotit != Dummy->ballotbox.end(); ballotit++)
{
// 자기 자신의 정보를 삭제하고.
(*ballotit).erase((*ballotit).begin());
// 투표용지를 다음 사람에게 넘긴다.
this->candidates[((*ballotit)[0])-1]->ballotbox.push_back((*ballotit));
}
// 자신이 용지를 폐기처리.
for( ballotit = Dummy->ballotbox.begin(); ballotit != Dummy->ballotbox.end(); ballotit++)
(*ballotit).erase((*ballotit).begin(), (*ballotit).end());
Dummy->ballotbox.erase(Dummy->ballotbox.begin(), Dummy->ballotbox.end());
}
}
}
void Release(void)
{
CANDIDATES ::iterator it;
for(it = this->candidates.begin(); it != this->candidates.end(); it++)
{
Candidate* Dummy = (*it);
BALLOT_BOX ::iterator ballotit;
for( ballotit = Dummy->ballotbox.begin(); ballotit != Dummy->ballotbox.end(); ballotit++)
(*ballotit).erase((*ballotit).begin(), (*ballotit).end());
delete (*it);
Dummy->ballotbox.erase(Dummy->ballotbox.begin(), Dummy->ballotbox.end());
}
this->candidates.erase(this->candidates.begin(), this->candidates.end());
}
};
void main(void)
{
PollingPlace pp;
bool Keep = true;
while(Keep)
{
string cmd;
::getline(cin, cmd);
Keep = pp.CmdLine(cmd);
}
}
try catch는 머나먼 곳으로...
언제나 메모리 해제 하는 부분에서 문제가 생기는거 같다.