您的位置:首页 > 编程语言 > Go语言

pongo(英雄会)题解之均分01

2013-12-27 14:21 225 查看

这道题我没想到好的方法,今天翻群里面的聊天记录,看到了关于这题的讨论。下面解法的思想是借鉴了群里面超然_烟火 的想法,我只是用自己的方法证明了下,下面是题目描述:

题目详情:

给定一个字符串,长度不超过100,其中只包含字符0和1,并且字符0和1出现的次数都是偶数。你可以把字符串任意切分,把切分后的字符串任意分给两个人,让两个人得到的0的总个数相等,得到的1的总个数也相等。
例如,输入串是010111,我们可以把串切位01, 011,和1, 把第1段和第3段放在一起分给一个人,第二段分给另外一个人,这样每个人都得到了1个0和两个1。我们要做的是让切分的次数尽可能少。
输入是这样一个字符串,输出是最少的切分次数,保证输入合法。
注:题目一定有解,因为我们最差情况时,把字符串切分(n - 1)次形成n个长度为1的串

------------------------------------------------------------------------------------------------------------
假设将这个字符串的头与尾部相连接,那么构成一个字符串圆环,在这个圆环中存在这样一个规律:
必定存在这样一条直径,以这条直径将圆环分成两部分,使得这两部分的0的个数相同,且1的个数相同。

证明:(过程是以任一条直径开始,顺时针旋转这条直径,直到合适位置)
因为0和1的个数都是偶数,那么设1的个数为2n,0的个数为2m;
先以其中任一条直径将圆环分为两部分(如下图),不妨将左边的半圆成为L,右边的半圆称为R:




那么我们不妨设L中0的个数不足,1的个数超量,L和R中的0,1个数如下:
0个数 1个数
L中 m-x n+x
R中 m+x n-x

接下来我们旋转这条直径,旋转时无非下面四种情况:




其中第1、4种情况不会影响旋转前L和R中的0、1个数,第2、3中情况才会影响L和R中的0、1个数,那么旋转前L和R中的数字对应情况如何?
(对应指分别在一条直径的两端)

假设L中0对应R中1 即上图第3种情况 的次数为b,那么有:
L中0对应R中0 即上图第1种情况 的次数为m-x-b,
L中1对应R中1 即上图第4种情况 的次数为n-x-b,
L中1对应R中0 即上图第2种情况 的次数为2x+b

因为L中缺少x个0,那么 我们只要保证在旋转的过程中出现第2种情况的次数比出现第3种情况的次数多x次,就能使得L中的0、1个数分别与R中的相等,而上面我们已经推导出第二种情况存在2x+b次,第3种情况存在b次,那么在寻转过程中肯定存在“出现第2种情况的次数比出现第3种情况的次数多x次”的情况,得证。

基于上面的规律,我们得出最多需要两刀就能将字符串均分:其中前半字符串与后半字符串的0、1个数均相等时,只需一刀;其他情况只需2刀。

代码如下:

#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
class Test {
public:
    static int howmany (string   s){
        int numL=0;
		int numR=0;
		int end=s.size()/2;
		int rev=s.size()-1;
		for(int i=0;i<end;i++){
			if('1'==s[i])
				numL+=1;
			if('1'==s[rev-i])
				numR+=1;
		}
		if(numL==numR)
			return 1;
		return 2;
    }
};
//start 提示:自动阅卷起始唯一标识,请勿删除或增加。
int main()
{   
    cout<<Test::howmany("010100")<<endl;   
} 
//end //提示:自动阅卷结束唯一标识,请勿删除或增加。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: