一、简单枚举
【例题1】:输入一个整数n,按从小到大的顺序输出所有形如abcde/fghij=n的表达式,其中a~j恰好为数字0~9的一个排列(可以有前导0),2<=n<=79。
代码如下:
#include
#include
bool vis[10];//【visit数组】用下标判断数字是否已经被访问过;
char str[15];//vis里的数字是按照0123456789的顺序,str是按照a和b给定的顺序
bool check(int a, int b)
{
sprintf(str, "%05d%05d", a, b);
//【格式化字符串】int sprintf( char *buffer, const char *format [, argument] ... )。除了前两个参数类型固定外,后面可以接任意多个参数,这取决于第二个参数需要几个后继参数。而它的精华,显然就在第二个参数:【格式化字符串】上。
memset(vis, 0, sizeof(vis));
//【memse】t:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行【清零操作】的一种最快方法。它有三个参数,一是所要set的首地址,二是set的值,三是set的字节数,vis肯定是个数组,因为数组在传参时能自动转成指向数组的首元素的指针,如果不是数组,应该写成memset(&vis, 0, sizeof(vis));
for (int i = 0; i < 10; i++)
{
if (vis[str[i]-'0']) return false;//如果已访问,返回false
vis[str[i]-'0'] = true;//未访问,改变该数字对应的访问数组的值
}
return true;
}
int main()
{
int n;
bool first = true;
while (scanf("%d", &n) && n)
{
bool exist = false;
if (first) first = false;
else printf("\n");
for (int i = 1234; i <= 98765; i++)
{ //这里设abcde为A,fghij为B。没有必要枚举0~9的所有排列,只需枚举B就可以算出A,然后判断是否所有数字 不相同即可。
int ans;
if (i % n == 0) //A可以整除n就说明这样的B存在,可以继续计算
{
ans = i / n;//计算出B;
if (ans < 1234) continue;//排除a<1234的情况;
if (check(i, ans))//判断是否符合各个位不相同
{
exist = true;
printf("%05d / %05d = %d\n", i, ans, n);//不足n位前补0:【%0nd】
}
}
}
if (!exist) printf("There are no solutions for %d.\n", n);
}
return 0;
}
总结:
1.暴力求解法并非是一味的暴力,本题中两个数之间有整除关系,只需确定一个;再利用每个数字都不同来筛选;
2.先找出满足整除条件的,然后筛掉不足1234的;
3.不会的知识点主要集中在【判断两个字符串中是否有重复数字】:
(1)格式化:用sprintf把两个数字格式化成一个字符串;
(2)memset函数的常用用法:对结构体或数组进行清零;
(3)visit数组记录该数字是否被访问过,一旦visit[str-‘0’]的值被改编为true,即可返回false,排除这一组答案。
4.所谓的暴力并不是全暴力,要适当的节省时间空间,其中可能还穿插着一些小技巧。
【例题2】:输入n个元素组成的序列S,你需要找出一个乘积最大的连续子序列。如果这个最大的乘积不是正数,应输出0(表示无解)。1<=n<=18,-10<=Si<=10。
分析:连续子序列--->联想到两要素:起点和终点--->只需枚举起点和终点。
代码如下:
#include
#include
using namespace std;
int main()
{
int t,number,i,j,n,a[20];
long long ans,max1;
number=0;
while(scanf("%d",&n)!=EOF)
{
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
max1=0;
for(i=1;i<=n;i++)
{
ans=a[i];
if(ans>max1)
max1=ans;
for(j=i+1;j<=n;j++)
{
ans*=a[j];
if(ans>max1) max1=ans;
}
}
printf("Case #%d: The maximum product is %lld.\n\n",++number,max1);
}
return 0;
}
总结:
无论是求拥有连续最大和还是积的子序列,思想都是一样的。需要设定一个当前积ans,一个最大积max,第一重循环先固定第一个位置不动,把a[i]的值赋给ans,如果ans>max,就改变max的值为ans的值(也就是说,如果在这里改变了max的值,最大子序列的第一个位置就要发生变化)。嵌套在其中的第二重循环用于确定末位置,ans=ans*a[j],同样的,如果ans>max,就改变max的值为ans的值。
如果还要添加功能,即记录最大子序列的起始位置和终止位置,则还需要两个变量start,end......(未完待续)