摩尔投票法

洛谷 P2397

自动上次 redbag 用加法好好的刁难过了 yyy 同学以后,yyy 十分愤怒。

他还击给了 redbag 一题,但是这题他惊讶的发现自己居然也不会,所以只好找你

一共有 \(n\) 个正整数 \(a_i\),他让 redbag 找众数。他还特意表示,这个众数出现次数超过了一半。

摩尔投票法的基本思想很简单,在每一轮投票过程中,从数组中找出一对不同的元素,将其从数组中删除。这样不断的删除直到无法再进行投票,如果数组为空,则没有任何元素出现的次数超过该数组长度的一半。如果只存在一种元素,那么这个元素则可能为目标元素。

为了便于理解,我们想象一个情景,有一堆人在打架,我们假设每一个人的战斗力都是 \(1\)\(1\)。也就是 \(A\) 打死 \(B\)\(A\) 也会死。

假设只有 \(2\) 波人(我们把不是众数的数字看作一个数)且各占二分之一,显然继续打下去两边人都会死光。

但是我们现在有 \(2\) 波人,其中一波人特别多(一半以上),显然这波人必然是赢家,虽然不知道打完还剩几个,但一定会有剩下的。因为一换一。若第二波人有x个,则第一波人有(\(n-x\))个且 \(n-x>x\)。那么最后剩下的人就是 \(n-2x\) 个。假设这 \(2\) 波人头上顶着 \(2\) 个不同的数字,这个剩下的人的数字就是众数。

以上用于帮助理解代码。

所以我们可以把摩尔投票法看作一种抵消的思想,当前数字进场,然后和上一个判断,如果是同一个数计数器\(++\),如果不是计数器\(--\)

当计数器等于 \(0\) 时,\(ans\) 重新登记为新输入的数,进行抵消的操作,最后剩下的一定是众数(但众数必须满足大于总数的一半)。

#include <bits/stdc++.h>
using namespace std;
int n, x, ans, y = 0;
int main()
{
  scanf("%d", &n);
  for (int i = 1; i <= n; i++)
  {
    scanf("%d", &x);
    if (y == 0)
      ans = x;
    if (ans == x)
      y++;
    if (ans != x)
      y--;
  }
  printf("%d", ans);
  return 0;
}