SDNU-OJ:1095.Ignatius and the Princess IV

原题:http://www.acmicpc.sdnu.edu.cn/problem/show/1095

Description

  • “OK, you are not too bad, em… But you can never pass the next
    test.” feng5166 says. “I will tell you an odd number N, and then N
    integers. There will be a special integer among them, you have to
    tell me which integer is the special one after I tell you all the
    integers.” feng5166 says. “But what is the characteristic of the
    special integer?” Ignatius asks. “The integer will appear at least
    (N+1)/2 times. If you can’t find the right integer, I will kill the
    Princess, and you will be my dinner, too. Hahahaha…..” feng5166
    says. Can you find the special integer for Ignatius?

Input

  • The input contains several test cases. Each test case contains two
    lines. The first line consists of an odd integer N(1<=N<=999999)
    which indicate the number of the integers feng5166 will tell our
    hero. The second line contains the N integers. The input is
    terminated by the end of file.

Output

  • For each test case, you have to output only one line which contains
    the special number you have found.

Sample Input
5
1 3 2 3 3
11
1 1 1 1 1 5 5 5 5 5 5
7
1 1 1 1 1 1 1

Sample Output
3
5
1

题意理解:
大意是给出了N个数,N是一个奇数,这N个数中有一个特殊的数,这个特殊的数具有的性质是至少出现了(N+1)/2次。需要我们找出这个数。

一开始有以下几种思路:
1.由于给出了N的范围,因此想定义一个长度大于N的数组,输入的数作为下标,例如:输入一个i,那么a[i]++。输入完成后for循环跑一遍,找到a[j]的值最大的然后输出j即可。但是数组的长度太大,显然不能这么做。
2.开一个map,每次输入一个j,就查找j=m[key],如果不存在就建立一个,每次输入都由指针指向已存在或建立的m[j].second使其加一,使用greater排序second值,最后输出第一个m就OK了……想的很美好,没写就放弃了。
3.由于一共有奇数个元素,最多的元素的个数还大于N/2,那么就可以两两分一组还剩下一个,不同的元素就相互抵消掉,相同的元素就继续保留,继续分组抵消保留……最后剩下的肯定就是个数最多的那个值。

硬着头皮分情况想了一下:
1.前N-1个元素是N/2个x和N/2个其他元素组成,第N个元素是一个x。N/2个其他元素如果是存在不相同的话那么内部就会存在相互抵消,这样剩下的相同的元素的个数就会小于N/2,然后与N/2个x作抵消的时候肯定会剩下x,然后第N个元素还是x,那这样最多的就是x了。如果N/2个元素都相同的话,作个计数器c,相同的就+1,不同的就-1,然后N/2个相同的元素取完就是N/2了,然后遇到连续N/2个x就会连续减去N/2,最后顶多是个0,然而第N个元素还是x,最多的元素依旧是x。
2.以上是以x元素全都堆在一起,非x元素也都堆在一起的结果。如果x和非x非完全交叉出现时,依旧使用计数器c,当非x元素的值不同的时候依旧会发生内部抵消,剩下的结果肯定是x;那么如果非x元素的值相同的话,从头开始计数,若非x就减一,若是x就加一,两个元素的个数相同,那么最后还是0,第N个元素还是x,结果还是x。
如果第N个不是x,那就取前N-1中的一个x与第N个交换,再进行以上讨论。

找到这个规律之后总结一下发现:无论这个数列怎么排序,都是要求从其中取出能让最后与x抵消掉最多的情况(如果取出两个非x的不同元素必定是x最多,如果取出的是相同的就放回去),因为N是一个奇数而且x的个数大于N/2,那么无论怎么取都会剩下至少一个x,那就是x代表最多的。

对于这个题,不妨使用上文中提到过的一个计数器:使用for循环遍历整个数组,计数器c从0开始,如果c的值为0的时候就用m记录下当前输入的数的值并且c加一,如果c的值不为0的时候就,对于输入的值如果和记录的m的值相同c就继续加一体现放回,不相同的话就减一来体现抵消,注意只有当c这个计数器归零代表前面的全都抵消掉的时候才会记录新的m,由于一共奇数个数,那么c最后一定不为0,最后一次记录下的m就是最多的那个数。

甚至做出了以下联想,N个小球放进一个袋子里(N为奇数),其中有至少1+N/2个相同的小球在袋子中,剩下的小球可以相同也可以不相同,问个数最多的小球是哪种?
可以进行这样的操作:每次取出两个小球,如果两个小球相同的话就放进另一个备用袋子中,如果两个小球其中一个和备用袋子中的相同另一个不相同的话就都取出来弃掉,如果两个小球都不和备用袋子中的小球相同的话就从备用袋子中取出两个小球组成4个配对取出弃掉,不断更新备用袋子,最后从袋中取出最后一个小球的时候如果和备用袋子里小球不同就从备用袋子中取出一个,备用袋子中剩下的小球就是最多的小球;如果最后从袋子中取出的小球和备用袋子中的小球相同的话也就找到了最多的小球。

重点是:使用一个计数器,出现后面的相同x就加一,不同就减一,当c为0的时候就重新计数(因为是奇数个,最后肯定为1)。

#include 
int main()
{
    int n;
    while(scanf("%d",&n) != EOF)
    {
        int c = 0, m, t;
        for(int i = 0; i < n; i++)
        {
            scanf("%d", &t);
            if(c == 0)
            {
                m = t;
                c++;
            }
            else
            {
                if(t == m)
                {
                    c++;
                }
                else
                {
                    c--;
                }
            }
        }
        printf("%d\n", m);
    }
    return 0;
}

你可能感兴趣的:(散题)