Programming Challenges 习题 1.6.8

PC/UVa:110108/10142

Australian Voting

根据题目的过程模拟选举过程就可以了,但是也有几个注意的点:

  • 得票为0的候选人出局
  • 某个候选人票数大于50%时,选举胜利,此时只可能有一个人
  • 当这一轮统计过后没有人出局时,也就是最小票数和最大票数相同时,即为平局的情况

每个候选人的票存在ticket数组中,viOrder表示每张选票的首选项,sCandidate表示未出局的候选人。

循环中首先统计当前这一轮的首选项的结果,存储在mulmapCandidate2Voter中。这是一个二元组组成的多重映射,第一维表示候选人编号,第二维表示此轮的选票号。使用多重映射可以很方便的得到每个候选人得票数,以及对应的选票号。

第二步是计算最大票数和最小票数,同时建立票数到候选人的映射mulmapTickets2Candidate。这个映射中二元组的第一维表示此轮选票数目,第二维表示相应候选人编号。使用此映射可以从最小的票数找到对应的候选人,然后在使用上段中的映射就可以找到需要重新统计的选票。

第三步是计算是否有人胜出,或者是否为平局。

第四步是重新统计选票。使用mulmapTickets2Candidate可以找到这一轮中出局的候选人,将其加入到sOuter中,并从sCandidate中去除。然后对于这一轮出局的每一个候选人,通过mulmapCandidate2Voter找到对应的选票,更新每张选票的首选项(viOrder),然后重新统计下一轮。

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <map>
#include <set>

using namespace std;

void vote()
{
	int n = 0, total = 0;
	cin >> n;
	cin.get();
	vector<string> vecstr(n, "");
	vector<int> viOrder(1000, 0);
	string strLine;
	int ticket[1000][20] = { 0 };
	set<int> sCandidate;
	for (int i = 0; i < n; i++)
	{
		getline(cin, vecstr[i]);
		sCandidate.insert(i);
	}
	while (getline(cin, strLine)){
		if (strLine.empty()) break;
		istringstream iss(strLine);
		for (int i = 0; i < n; i++)
		{
			iss >> ticket[total][i];
			ticket[total][i]--;
		}
		total++;
	}
	int candidate, voter, outer;
	while (1){
		int max = 0, get = 0, min = 1000;
		multimap<int, int> mulmapCandidate2Voter;
		multimap<int, int> mulmapTickets2Candidate;
		set<int> sOuter;
		//统计这一轮所有候选人的得票
		for (voter = 0; voter < total; voter++)
		{
			if (viOrder[voter] == n) continue;
			candidate = ticket[voter][viOrder[voter]];
			mulmapCandidate2Voter.insert(pair<int, int>(candidate, voter));
		}
		//计算最高票和最低票数目,并建立从票数到候选人的多重映射
		for (set<int>::iterator iter = sCandidate.begin(); iter != sCandidate.end(); iter++)
		{
			get = mulmapCandidate2Voter.count(*iter);
			if (get > max) max = get;
			if (get < min) min = get;
			mulmapTickets2Candidate.insert(pair<int, int>(get, *iter));
		}
		//如果最高票数超过了50%则选举胜出
		if (max * 2 > total){
			cout << vecstr[mulmapTickets2Candidate.find(max)->second] << endl;
			return;
		}
		else if (max == min){//平局
			for (multimap<int, int>::iterator iter = mulmapTickets2Candidate.lower_bound(max);
				iter != mulmapTickets2Candidate.upper_bound(max); iter++)
			{
				cout << vecstr[iter->second] << endl;
			}
			return;
		}
		//票数最低的候选人出局
		for (multimap<int, int>::iterator iter = mulmapTickets2Candidate.lower_bound(min);
			iter != mulmapTickets2Candidate.upper_bound(min); iter++)
		{
			outer = iter->second;
			sOuter.insert(outer);
			sCandidate.erase(outer);
		}
		//更新需要重新统计的选票的首选项
		for (set<int>::iterator iter1 = sOuter.begin(); iter1 != sOuter.end(); iter1++)
		{
			outer = *iter1;
			for (multimap<int, int>::iterator iter2 = mulmapCandidate2Voter.lower_bound(outer);
				iter2 != mulmapCandidate2Voter.upper_bound(outer); iter2++)
			{
				voter = iter2->second;
				while (++viOrder[voter] != n){
					candidate = ticket[voter][viOrder[voter]];
					if (sCandidate.find(candidate) != sCandidate.end()){
						break;
					}
				}
			}
	
		}
	}
}

int main()
{
	int n = 0;
	cin >> n;
	cin.get();
	cin.get();
	for (int i = 0; i < n; i++)
	{
		vote();
		if (i != n - 1) cout << endl;
	}
}
/*
2

3
John Doe
Jane Smith
Jane Austen
1 2 3
2 1 3
2 3 1
1 2 3
3 1 2

5
A
B
C
D
E
4 1 3 2 5
1 4 3 5 2
5 4 2 1 3
5 1 4 2 3
2 3 1 5 4
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值