最近看到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;
}
这样虽然能够得到结果,但是效率太低,希望大家一起来交流一下。
第一次写博客,不喜勿喷啊!!!!