forked from nihavi/CRElection
-
Notifications
You must be signed in to change notification settings - Fork 1
/
stv.cpp
160 lines (147 loc) · 4.33 KB
/
stv.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include<bits/stdc++.h>
using namespace std;
typedef vector<int> vi;
typedef pair<int,int> pii;
typedef long long int lld;
#define sz size()
#define pb push_back
#define mp make_pair
#define F first
#define S second
#define fill(a,v) memset((a),(v),sizeof (a))
#define INF INT_MAX
#define mod 1000000007
#define __sync__ std::ios::sync_with_stdio(false);
#define all(a) a.begin(),a.end()
typedef long double ld;
//Total number of people voting
int S;
//Total number of people supposed to win
int N;
ld t; //threshold
vector<string> winners;
vector< stack<string> > ballots;
//in the top down order of each persons preference
map<string, ld> votes; //map because I dont know input format
map<string, bool> notInContention; //whether he/she is still in the race
/*
* Transfer votes down from 'name', who has received k >= t votes
*/
void transferDown(string name, ld k)
{
ld f = (k - t)/k;
for (auto &b : ballots)
{
while (!b.empty() && notInContention[b.top()]) b.pop();
if (!b.empty() && b.top() == name)
{
b.pop();
while (!b.empty() && notInContention[b.top()]) b.pop();
if (!b.empty())
{
votes[b.top()] += f;
}
}
}
}
/*
* Transfer votes up from 'name', who got least votes in a stage and so, was eliminated.
*/
void transferUp(string name, ld k)
{
for (auto &b : ballots)
{
while (!b.empty() && notInContention[b.top()]) b.pop();
if (!b.empty() && b.top() == name)
{
b.pop();
while (!b.empty() && notInContention[b.top()]) b.pop();
if (!b.empty())
{
votes[b.top()] += 1;
}
}
}
}
void getWinners()
{
t = (int)(1.0 * S / (N + 1)) + 1;
int left = N;
printf("electorate attendance: %d, threshold: %Lg\n", S, t);
while ((int)winners.sz < N)
{
printf("============\nVotes:\n");
for (auto v: votes) {
printf("%s: %Lg\n", v.F.c_str(), v.S);
}
printf("============\n\n");
if ((int)votes.sz <= left)
{
for (auto elem : votes) winners.pb(elem.F);
return;
}
auto it = *max_element(votes.begin(), votes.end(),
[](const pair<string, ld>& p1, const pair<string, ld>& p2) {return p1.second < p2.second; });
if (notInContention[it.F]) continue;
printf("Candidate %s has max votes (%Lg)\n", it.F.c_str(), it.S);
if (it.S >= t)
{
printf("Candidate wins! (%Lg > %Lg), transferring down\n", it.S, t);
transferDown(it.F, it.S);
winners.pb(it.F);
notInContention[it.F] = 1;
votes.erase(it.F);
left--;
}
else
{
printf("Not enough votes to win (%Lg not greater than %Lg)\n", it.S, t);
auto x = *min_element(votes.begin(), votes.end(),
[](const pair<string, ld>& p1, const pair<string, ld>& p2) {return p1.second < p2.second; });
printf("Candidate %s has min votes (%Lg), transferring votes up\n", x.F.c_str(), x.S);
transferUp(x.F, x.S);
notInContention[x.F] = 1;
votes.erase(x.F);
}
}
}
void parse(string s)
{
stack<string> tmp;
vector<string> tmp1;
int x = 0;
int f = 1;
while (x < s.length())
{
string name = "";
while (x < s.length() && s[x] != ' ') name += s[x++];
tmp1.pb(name);
if (f) votes[name]++, f = 0;
else votes[name];
x++;
}
for (int i=(int)tmp1.sz-1;i>=0;i--) tmp.push(tmp1[i]);
ballots.pb(tmp);
}
int main(int argc, char** argv)
{
S = 0;
if (argc < 3) {
printf("usage: stv <votes file> <delegation size>\n");
return 1;
}
ifstream in(argv[1]);
N = atoi(argv[2]);
printf("Delegation size: %d\n", N);
while (!in.eof())
{
string line;
getline(in, line);
parse(line);
S++;
}
S -= 1; // correction for off-by-one error due to eof()
getWinners();
printf("============\nWinners are:\n");
for (string &w : winners) cout << w << "\n";
}