明确最重要的一点:每个小孩间都存在胜负关系,非胜则负。而小孩王的条件是该小孩不惧怕任何其他的小孩,即其打败的小孩(直接打败)加上他打败的小孩打败了的小孩(间接打败)之和等于其他小孩的总数。
就以上而言,题目是比较简单的,只需要对每个孩子都进行二步深搜即可,但这样会超时。关键在于找到个中的规律。
如果至少存在一个小孩王,可以假设出度(直接打败其他小孩的人数)最大的那个小孩是小孩王之一。对于这个假设,用反证法证明:假设出度最大的那个(用A表示)不是小孩王,就表示A直接打败了的n个人中,没有人能打败B,而B又打败了A,这样A就惧怕B,故A不是小孩王。上面的论述中,明显可以发现B打败了A打败了的n个人并且打败了A,那么B的出度就是n+1,比A的n大,则A不是出度最大的那个,与前提矛盾,可知假设成立。所以,只要寻找这个小孩并输出即可。
如果不存在小孩王,仍然按照上述假设,若A不是小孩王,则存在出度比A大的B,若B还不是,则存在出度比B还大的C,如果这种情况一直存在,则依次类推直至最后一个小孩,若此小孩不是小孩王,则存在出度比这个小孩还大的,但由上面的推断可知最后一个小孩的出度是最大的,不可能存在出度还要大的情况;故此小孩一定是是小孩王,这样就与题设矛盾了。以此反证,可知必定存在至少一个小孩王。
综上而言,直接找出出度最大的那个小孩就是最后的答案。
Run Time: 0.04sec
Run Memory: 304KB
Code length: 593Bytes
SubmitTime: 2011-12-07 23:57:07
// Problem#: 2012
// Submission#: 1049697
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
int n;
int i, j, k;
char s[ 1000 ];
int out, max, king;
while ( scanf( "%d", &n ) != EOF ) {
king = 0;
max = 0;
for ( i = 0; i < n; i++ ) {
out = 0;
scanf( "%s", s );
for ( j = 0; j < n; j++ ) {
if ( s[ j ] == '1' )
out++;
}
if ( out > max ) {
king = i;
max = out;
}
}
printf( "%d\n", king + 1 );
}
return 0;
}
本文探讨了如何通过二步深搜找出小孩王的过程,并利用反证法证明了小孩王的存在性,最后提供了代码实现。
767

被折叠的 条评论
为什么被折叠?



