csdn编程挑战 比赛分数

最近看到csdn上的这个题目,题目描述如下:

n个人打乒乓球,每两个人都比赛一场,输者不得分,赢者得1分,最终记录n
个人的得分。但是记录有些缺失,即有些人的得分不见了,你能计算有多少种可能的得分?
矗?输入格式: 多组数据,每组数据两行,第一行是一个正整数n,表示比赛的人数,1 
<= N <=40。 第二行是N个空格分隔的整数,每个整数在-1到(N-1)之间,-1
表示这个人的分数缺失了,非负数表示得分。 输出格式: 
每组数据一行,表示满足条件的得分结果,因为结果比较大,输出对1000000007
取余数的结果。 
挑战规则: 
输入样例 3   -1 -1 2   3   -1 -1 -1   4   0 1 2 3   2   1 1   输出样例: 2 7 
1 0 解释: 第一组 得分可能是{0,1,2} 和 {1,0,2} 第二组 得分可跟是{1,1,1}, {0,1,
2}, {0,2,1}, {1,0,2}, {1,2,0}, {2,0,1}, {2,1,0} 第三组 只能是{0,1,2,3} 
第四组 两个人只能是{1,0} {0,1} 


由于没有怎么做过算法问题,这里想到的第一个问题就是:怎么计算出n个人总共有多少种比赛结果,

显然,每个人的得分应该是在(0,n-1)区间里,并且每两个人只比赛一场,所以还要满足:

1.最多有一个人得分为0

2.最多有一个人得分为n-1

这样就有了思路:

递归依次计算每个人为(0, n-1)时可能的结果数, 相加得到总的结果数。

#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
//确定数组是否满足限制  
int bConf(int arr[], int len)
{
	int i ,j;
	int sum = 0;
	int tol = len*(len-1)/2;
	int max = 2*(len-1);
	int tmp;
	for (i = 0; i < len; i++)
	{
		sum += arr[i];
		for(j = i+1; j < len; j++)
		{
			tmp = arr[i]+arr[j];
			if (tmp < 1 || tmp > max)//每两个人的得分和必须在在(1,2*(len-1))区间内 
				return 0;
		}
	}
	if (sum == tol)
		return 1;
	return 0;
}
int asum(int arr[], int len)
{
	int sum = 0;
	int i;
	for(i = 0;i < len; i++)
	{
		sum += arr[i];
	}
	return sum;
}
long func( int arr[], int len, int tsum, int pos)
{
	int i = 0;
	long result = 0;
	int tmp;
	int toltal = len*(len-1)/2;
	int max = 2*(len-1);
	int arra[40] = {-1};
	memcpy(arra, arr, len*sizeof(int));
	if (pos >= len - 1)
	{//最后一个人时 
		tmp = toltal - asum(arra, len-1);
		if (arra[pos] == -1)
		{
			if (tmp >= 0 && tmp < len)
			{//如果分数没有,则它的得分只能是总分数 - 前面所有人得分总和  
				arra[pos] =  tmp;
				return bConf(arra, len);
			}
			return 0;
		}
		else if(tmp == arra[pos])
		{//如果分数确定,确定这组得分是否满足限制  
			return bConf(arra, len);
		}
		return 0;
	}
	if (arra[pos] == -1)
	{
		for (i = 0; i < len; i++)
		{
			tmp = tsum + i;
			if (tmp >= pos && tmp <= (toltal - len + pos + 2))
			{//从0-pos元素的和必定大于等于pos,因为只能有一个元素为0,其他的都大于0 
				arra[pos] = i;
				result += func(arra, len, tsum + i, pos+1);
			}
		}
	}
	else
	{
		tmp = tsum + arra[pos];
		if (tmp >= pos && tmp <= (toltal - len + pos + 2))
		{
			return func(arra, len, tsum+arra[pos], pos+1);
		}
		return 0;
	}
	return result%1000000007;
}

int main()
{
	int arr[40] = {-1};
	struct timeval start, stop;
	long int tmp;
	int i, j;
	int a[3] = {-1, -1, 2};
	int b[4] = {0,1,2,3};
	int c[2] = {1,1};
	printf("%d->%d\n", 2, func(c, 2, 0, 0));
	printf("%d->%d\n", 3, func(a, 3, 0, 0));
	printf("%d->%d\n", 4, func(b, 4, 0, 0));
	for(i = 2;i<41;i++)
	{
		for(j = 0; j < i; j++)
		{
			arr[j] = -1;
		}
		gettimeofday(&start, NULL);
		printf("%d->%d\n", i, func(arr, i, 0, 0));
		gettimeofday(&stop, NULL);
		tmp = stop.tv_sec - start.tv_sec;
		tmp = tmp*1000000 + stop.tv_usec - start.tv_usec;
		printf("consume %f \n", (float)tmp/1000000);
	}
	return 0;
}
这样虽然能够得到结果,但是效率太低,希望大家一起来交流一下。

第一次写博客,不喜勿喷啊!!!!






评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值