码迷,mamicode.com
首页 > 其他好文 > 详细

宇宙条面试题-枪手打靶问题

时间:2020-07-06 01:30:12      阅读:106      评论:0      收藏:0      [点我收藏+]

标签:open   ons   pac   err   eof   面试   tor   return   试题   

问题描述

每次打靶会有0到10的得分,问打10次恰好得90分有多少种打法

问题简化

每次打靶会有0到2分的得分,问打3次恰好得4分有多少种打法

分析

打一次

得分情况组合方式
0分(0)

1分(1)

2分(2)

打俩次

得分情况组合方式

0分 (0,0)

1分 (1,0),(0,1)

2分 (2,0),(1,1),(0,2)

3分 (2,1),(1,2)

4分(2,2)

由上可以看出,计算俩枪打完后得分组合数时,必须先把第一枪的得分组合数计算出来。

第二枪开完后得2分的组合数

第一枪得0分组合数 + 第一枪得1分得组合数 + 第二枪得2分得组合数

第二枪开完后得3分的组合数

第一枪 得2分组合数 + 第一枪得1分得组合数

由此有下面表格

1、行表示开枪的次数

2、列表示组合数

3、列下表表示得分

0 1 2 3 4 5 6
0 枪 0 0 0 0 0 0 0
1枪 1 1 0 0 0 0 0
2枪 1 2 3 2 1 0 0
3枪 1 3 6 7 6 3 1

泛化

每次打靶会有0到k分的得分,问打i次恰好得j分有多少种打法

条件约束 0<=j<=k*i

1、每一枪得分范围是0-k

2、i枪得分范围是i*k

3、( i - 1 )枪得分范围是 k *( i - 1)

设 C[i][j] 表示 打完i枪后,得分恰好是j分的打法

C [ i ][ j ] = C[ i - 1 ][ j - 0 ] + C[i-1][j-1]+.......+C[i-1][ j - k ]

公式含义

C[ i - 1 ][ j ] 是i-1枪总得j分,第i枪得0分

C[i-1][j-1] 是i-1枪总的j-1分,第i枪得1分

C[i-1][ j - k] 是i-1枪得j-k分,第i枪得k分

由此有代码如下

#include <string>
#include<iostream>
#include <sstream>
#include<map>
#include<set>
#include<memory.h>
#include<vector>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#include<math.h>
#include<iomanip>
#include<bitset>
#include"math.h"
namespace cc
{
	using std::cout;
	using std::endl;
	using std::cin;
	using std::map;
	using std::set;
	using std::vector;
	using std::string;
	using std::sort;
	using std::priority_queue;
	using std::greater;
	using std::vector;
	using std::swap;
	using std::stack;
	using std::bitset;
	using std::stringstream;
	using std::abs;

	int solve(int num, int score) {
		const int MAX_SCORE = 100;
		const int MAX_NUM = 10;
		int c[MAX_NUM][MAX_SCORE];
		//一枪可以得分0-k
		//const int k = 9;
		
		const int k = 2;
		if (k * num < score || score < 0 || score >= MAX_SCORE) {
			cout << "error input" << endl;
			return -1;
		}
		memset(c, 0, sizeof(c));
		//
		for (int j = 0; j <= k; j++) {
			//第一枪
			c[1][j] = 1;
		}
		//得分0
		for (int j = 1; j <= num; j++) {
			c[j][0] = 1;
		}

		//第i枪
		for (int i = 2; i <= num;i++) {
			//当前最大得分是i * k 
			int maxScore = i * k;
			//j分
			for (int j = 1; j <= maxScore;j++) {
				//当前j得分组合数
				int sum = 0;
				for (int t = 0; t <= k; t++) {
					sum = sum + c[i - 1][j - t];
				}
				c[i][j] = sum;
			}
		}
		return c[num][score];
	}
}


int main()
{

#ifndef ONLINE_JUDGE
	freopen("d://1.text", "r", stdin);
	//freopen("d://1.out","w",stdout);
#endif // !ONLINE_JUDGE
	int num = 3, score = 5;
	int ans = cc::solve(num,score);
	std::cout << ans << std::endl;
	return 0;
}

优化

公式1

C [ i ][ j ] = C[ i - 1 ][ j ] + C[i-1][j-1]+......+C[i-1][ j - (k-1)]+C[i-1][ j - k]

忽略下标i,项的排列如下

   	j, j-1,  j-2,  j-3....  j-(k-1),j-k

当j=j+1时

项的排列如下

j+1,   (j+1)-1,  (j+1)-2,(j+1)-3,(j+1)-4..... (j +1) - (k-1),(j+1) - k

化简有

j+1,   j,  j-1,j-1,..... j-(k-2),j - (k-1)

所以有

C [i][j+1] = C[i-1][j+1] + C[i][j] - C[i-1][j+1-(k+1)]

C [i][j] = C[i-1][j] + C[i][j-1] - C[i-1][j-(k+1)]

代码如下:

#include "pch.h"
#include 
#include
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"math.h"
namespace cc
{
	using std::cout;
	using std::endl;
	using std::cin;
	using std::map;
	using std::set;
	using std::vector;
	using std::string;
	using std::sort;
	using std::priority_queue;
	using std::greater;
	using std::vector;
	using std::swap;
	using std::stack;
	using std::bitset;
	using std::stringstream;
	using std::abs;

	int solve(int num, int score,int k) {
		const int MAX_SCORE = 1000;
		const int MAX_NUM = 20;
		int c[MAX_NUM][MAX_SCORE];
		//一枪可以得分0-k
		if (k * num < score || score < 0 ) {
			cout << "error input" << endl;
			return -1;
		}
		memset(c, 0, sizeof(c));
		//
		for (int j = 0; j <= k; j++) {
			//第一枪
			c[1][j] = 1;
		}
		//得分0
		for (int j = 1; j <= num; j++) {
			c[j][0] = 1;
		}

		//第i枪
		for (int i = 2; i <= num; i++) {
			//当前最大得分是i * k 
			int maxScore = i * k;
			//j分
			for (int j = 1; j <= maxScore; j++) {
				//当前j得分组合数
				int sum = 0;
				//枚举第i次得分
				for (int t = 0; t <= k; t++) {
					if (j-t>=0) {
						sum = sum + c[i - 1][j - t];
					}
				}
				c[i][j] = sum;
			}
		}
		return c[num][score];
	}


	int solve2(int num, int score,int k) {
		const int MAX_SCORE = 1000;
		const int MAX_NUM = 20;
		int c[MAX_NUM][MAX_SCORE];
		//一枪可以得分0-k
		if (k * num < score || score < 0) {
			cout << "error input" << endl;
			return -1;
		}
		memset(c, 0, sizeof(c));
		//
		for (int j = 0; j <= k; j++) {
			//第一枪
			c[1][j] = 1;
		}
		//得分0
		for (int j = 1; j <= num; j++) {
			c[j][0] = 1;
		}

		//第i枪
		for (int i = 2; i <= num; i++) {
			//当前最大得分是i * k 
			int maxScore = i * k;
			//j分
			for (int j = 1; j <= maxScore; j++) {
				//当前j得分组合数
				int d = 0;
				if (j - k -1 >= 0) {
					d = c[i - 1][j - k-1];
				}
				c[i][j] = c[i - 1][j] + c[i][j - 1] - d;

			}
		}
		return c[num][score];
	}
}


int main()
{

#ifndef ONLINE_JUDGE
	freopen("d://1.text", "r", stdin);
	//freopen("d://1.out","w",stdout);
#endif // !ONLINE_JUDGE
	int num = 10, score = 90;
	int k = 10;
	int ans=0;
	ans = cc::solve(num, score,k);
	std::cout << ans << std::endl;
	ans = cc::solve2(num, score,k);
	std::cout << ans << std::endl;
	return 0;
}

更优化一点

0 1 2 3 4 5 6
0 枪 0 0 0 0 0 0 0
1枪 1 1 0 0 0 0 0
2枪 1 2 3 2 1 0 0
3枪 1 3 6 7 6 3 1

由上有,找规律

宇宙条面试题-枪手打靶问题

标签:open   ons   pac   err   eof   面试   tor   return   试题   

原文地址:https://www.cnblogs.com/shuiyonglewodezzzzz/p/13252619.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!