第五周算法题整理

A - 利润

题目:

奶牛们开始了新的生意,它们的主人约翰想知道它们到底能做得多好。这笔生意已经做了
N(1≤N≤100,000) 天,每天奶牛们都会记录下这一天的利润 Pi(−1000≤Pi≤1000)。
约翰想要找到奶牛们在连续的时间期间(至少一天)所获得的最大的总利润,请你写一个计算最大利润的程序来帮助他。

Sample Input

7
-3
4
9
-2
-5
8
-3

Sample Output

14

思路:本题实质上可以看做求最大子数组问题

题解:

#include<bits/stdc++.h>
using namespace std;
int n,a[100005],f[100005];
int anss=-1000;
int main(void)
{
    
    
	cin >> n;
	for(int i=1;i<=n;i++)
	{
    
    
		cin >> a[i];
	}
	f[1]=a[1];
	for(int i=2;i<=n;i++)
	{
    
    
		f[i]=max(f[i-1]+a[i],a[i]);//求出第i天的最大利润
		anss=max(anss,f[i]);//表叫得出总共的最大利润
	}
	cout << anss ;
	return 0;
}

B - 取石子游戏

题目:

1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍。取完者胜.先取者负输出"Second win".先取者胜输出"First win".

Input

输入有多组.每组第1行是2<=n<2^31. n=0退出.

Output

先取者负输出"Second win". 先取者胜输出"First win".
参看Sample Output.

Sample Input

2
13
10000
0

扫描二维码关注公众号,回复: 13362502 查看本文章

Sample Output

Second win
Second win
First win

思路:
本题是“斐波那契博弈问题”,由于第一个人可以取任意数但不能取完,且第二个人可取的范围是 1~(第一个人取数的二倍)
PS:只要n是斐波那契数列中的数,那么先手必败
证明如下:
*将石子数量n记为f[i],
数学归纳法:

(1)当 i=2 时,先手的人只能取一个,那么先手必败,结论成立
(2)假设当 i<=k 时结论成立
则当i=k+1时,f[i]=f[k]+f[k-1],相当于我们将这堆石子看成两堆:k堆和k-1堆**
(之所以一定可以看成两堆,是因为假如先手第一次取的石子>=f[k-1],则后手可以直接取完获胜,因为 f[k]<2f]k-1])**
(3)对于k-1堆,无论先手怎么取,后手总能取到最后一个。设后手最后取到的石子数为x
如果先手第一次取的石子y>=f[k-1]/3, 则这堆石子剩余石子小于2y,就说明后手能一次取完剩余石子,此时x=f[k-1]-y,且x<=(2/3)f[k-1]
(4)由于接下来要取k堆中的石子了,所以比较一下 (2/3)f[k-1] 和 (1/2)f[k] 的大小,即比较 4f[k-1] 和 3
f[k]的大小
3
f[k] - 4f[k-1]=3f[k-2]-f[k-1]>0,即(1/2)f[k] 较大,
即 x < (1/2)*f[k],也就是说后手取完k-1堆后,先手不能一次取完k堆,所以游戏规则没有改变,同理得后手仍然能取到k堆的最后一课,所以结论成立。

以上是当n属于斐波那契数列 时,先手必败
当n不属于斐波那契数列时,根据“Zeckendorf定理”(查阅资料)得:
“任何正整数都可以表示为若干个不连续的斐波那契数之和”

题解:

#include<stdio.h>
int f[100];
int Fib(int n);
int main(void)
{
    
    
	int n,k;
	while(scanf("%d",&n))
	{
    
    
		if(n==0)
		{
    
    
			break;
		}
		k=Fib(n);
		if(k)
		{
    
    
			printf("Second win\n");
		}
		else
		{
    
    
			printf("First win\n");
		}
	}

	
	
	
	return 0;
 } 
 int Fib(int n)
 {
    
    
 	f[1]=1;
 	f[2]=1;
 	for(int i=3;i<=50;i++)
 	{
    
    
 		f[i]=f[i-1]+f[i-2];
		if(f[i]==n)
		return 1;
		if(f[i]>n)
		break;
	 }
	 return 0;
 }

猜你喜欢

转载自blog.csdn.net/qq_51368103/article/details/115307771
今日推荐