注:最近在学习刘汝明老师的《算法竞赛入门经典》,以下为相关整理的学习笔记内容
“暴力解决”——不用动太多脑筋,把所有可能性都列举出来,然后一一试验。尽管这样的方法显得很“笨”,但却常常是行之有效的。
一、除法
问题描述:输入正整数n,按照从小到大的顺序输出所有形如abcde/fghij=n的表达式,其中a~j恰好为数字0~9的一个排列,2<=n<=79。
样例输入:
62
样例输出:
79546/01283=62
94736/01528=62
分析:枚举0~9的所有排列?没有必要,只需要枚举fghij就可以算出abcde,然后判断是否所有数字都不相同即可。不仅程序简单而且枚举量也从10!=3628800降至不到1万。
由此可见,即使采用暴力枚举,也是需要认真分析问题的。
#include
#include
using namespace std;
bool check(int i,int j)
{
int n[10],flag=1;
n[0]=i%10,n[1]=i/10%10,n[2]=i/100%10,n[3]=i/1000%10,n[4]=i/10000%10;
n[5]=j%10,n[6]=j/10%10,n[7]=j/100%10,n[8]=j/1000%10,n[9]=j/10000%10;
sort(n,n+10);
for(int i=0;i<10;i++)
{
if(n[i]!=i)
{
flag=0;
break;
}
}
if(flag==1)
return true;
else
return false;
}
int main()
{
int n;
cin>>n;
int i,j;
for(i=1234;i<=98765;i++)
{
j = i*n;
if(j>=10234&&j<=98765)
{
if(check(i,j)==true)
{
if(i/10000%10&&j/10000%10)
cout<
二、最大乘积
问题描述:输入n个元素组成的序列S,你需要找出一个乘积最大的连续子序列。如果这个最大的乘积不是正数,应输出-1(表示无解)。-1<=n<=18,-10<=Si<=10。
样例输入:
3
2 4 -3
5
2 5 -1 2 -1
样例输出:
8
30
分析:连续子序列有两个要素:起点和终点,因此只需枚举起点和终点即可。由于每个元素的绝对值不超过10,一共又不超过18个元素,最大可能的乘积不会超过10^18,可以用long long存下。
#include
using namespace std;
int main()
{
long long s[20],num[20];
int n;
long long max;
while(~scanf("%d",&n))
{
s[0]=1;
for(int i=1;i<=n;i++)
{
cin>>num[i];
s[i] = s[i-1]*num[i];
}
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
if(s[j]/s[j-i]>max)
max = s[j]/s[j-i];
}
}
if(max<0)
max = -1;
cout<
三、分数拆分
输入正整数k,找到所有的正整数x>=y,使得1/k=1/x + 1/y;
样例输入:
2
12
样例输出:
2
1/2 = 1/6 + 1/3
1/2 = 1/4 + 1/4
8
1/12 = 1/156 + 1/13
1/12 = 1/84 + 1/14
1/12 = 1/60 + 1/15
1/12 = 1/48 + 1/16
1/12 = 1/36 + 1/18
1/12 = 1/30 + 1/20
1/12 = 1/28 + 1/21
1/12 = 1/24 + 1/24
从1/12=1/156+1/13可以看出,x可以比y大很多。由于x>=y,有1/x<=1/y,因此1/k-1/y<=1/y,即y<=2*k.这样,只需要在2*k范围之内枚举y,然后根据y尝试计算出x即可。
可以由题目推导得到 1/k<=2/y 即y<=2k
拆解题目的公式得到(y-k)/ky==1/x
#include
using namespace std;
int main()
{
int k;
cin>>k;
for(int y=k+1;y<=2*k;y++)
{
if((k*y%(y-k))==0)
{
int x=k*y/(y-k);
cout<<"1/"<