主题:请教一道题比较好的算法
yeknight
[专家分:1560] 发布于 2006-10-27 23:43:00
题目在:http://acm.pku.edu.cn/JudgeOnline/problem?id=1338
我是这样做的,但超时了,能提供一个比较好的算法马?
#include<iostream>
using namespace std;
const int N=1500;
int main()
{
int a[N],i=-1,j,k,m,n,max,b[3]={2,3,5},c[N];
do
{
i++;
cin>>a[i];
}while(a[i]);
max=a[0];
for(j=0;j<i;j++)
{
if(max<=a[j])
max=a[j];
}
c[0]=1;
k=1;
n=1;
while(k<max)
{
n++;
m=n;
while(m>1)
{
for(j=0;j<3;j++)
{
if(m%b[j]==0)
{
m=m/b[j];
j=-1;
}
}
if(j<3&&m>1)
continue;
if(j>=3&&m>1)
{
break;
}
if(m==1)
{
c[k]=n;
k++;
break;
}
}
}
for(j=0;j<i;j++)
cout<<c[a[j]-1]<<endl;
return 0;
}
回复列表 (共5个回复)
沙发
FancyMouse [专家分:13680] 发布于 2006-10-28 12:29:00
思路:一个Ugly Number只能由某个小一点的Ugly Number*2,*3,*5得到。
板凳
goal00001111 [专家分:4030] 发布于 2006-11-11 12:00:00
#include<stdio.h>
#include<stdlib.h>
#define MAX 800
int main(void)
{
unsigned long lib[MAX] = {1,};
unsigned long n, num;
int k = 1;
for (n=2; k<MAX; n++)
{
num = n;
while (num % 2 == 0)
num /= 2;
while (num % 3 == 0)
num /= 3;
while (num % 5 == 0)
num /= 5;
if (num == 1)
lib[k++] = n;
}
// int j;
// for (j=0; j<k; j++)
// printf("%ld\t", lib[j]);
unsigned int data[MAX] = {0};
int temp;
scanf("%d", &temp);
int len = 0;
while (temp != 0)
{
data[len++] = temp;
scanf("%d", &temp);
}
int i;
for (i=0; i<len; i++)
printf("%d\n", lib[data[i]-1]);
system("pause");
return 0;
}
3 楼
goal00001111 [专家分:4030] 发布于 2006-11-11 12:07:00
/*
算法分析:观察数列:
2 3 5
4 6 9 10 15 25
8 12 18 27 20 30 45 50 75 125
16 24 36 54 81 40 60 90 135 100 150 225 250 375 625
32 48 72 108 162 243 80 120 180。。。
可以看出每行依次递增3,4, 5,6。。。个元素。以第2行为例,递增的元素分别是
4 = 2 * 2, 6 = 3 * 2, 9 = 3 * 3,后面三个元素10,15,25分别由2,3,5各乘以5得到;
以第3行为例,递增的元素分别是
8 = 4 * 2, 12 = 6 * 2, 18 = 9 * 2,27 = 9 * 3;
后面三个元素20 30 45 50 75 125分别由4 6 9 10 15 25各乘以5得到;
由此可以得出规律:
设k表示栈顶,由于数组栈已经存储了4个元素{1,2,3,5,},则k初始值为4。
设第n(n>1)行最左边元素的下标为left,最右边元素的下标为right-1,sum表示第n行的元素个数,
其中n初始值为2,sum初始值为1。则对于第n行(n>1)来说,
sum += n; left = k - sum; right = k;
根据第n行的元素值,求出第n+1行的各个元素。
其中前n-1个元素为 for (i=left; i<left+n; i++)
lib[k++] = lib[i] * 2;
第n个元素为 lib[k++] = lib[left+n-1] * 3;
后面的sum个元素为 for (; left<right; left++)
lib[k++] = lib[left] * 5;
依此类推,直到存储了足够的元素。
注意:此处不能以k==MAX为结束标志,因为数组的元素不是递增排列的,有可能遗漏前面较小的元素。
解决方案是不接受较大的数(设其值为0),以便能全部求出前面较小的数。
最后对得到的数组进行排序,消去前面为0的元素。
一点疑惑:结果似乎有问题,但尚未找到原因
*/
#include<stdio.h>
#include<stdlib.h>
#define MAX 1500
int Move(unsigned long lib[], int len);
static int Compare(const void *p1, const void *p2)
{
return (*(unsigned long *)p1) - (*(unsigned long *)p2);
}
int main(void)
{
unsigned long lib[MAX*10] = {1,2,3,5,};
int left, right;
int k = 4;
int n = 2;
int sum = 1;
while (k < MAX)
{
sum += n;
left = k - sum;
right = k;
int i;
for (i=left; i<left+n; i++)
{
if (lib[i] * 2 < 2119458569) //若数值太大(溢出),则取0
lib[k++] = lib[i] * 2;
else
lib[k++] = 0;
}
if (lib[left+n-1] * 3 < 2119458569) //若数值太大(溢出),则取0
lib[k++] = lib[left+n-1] * 3;
else
lib[k++] = 0;
for (; left<right; left++) //若数值太大(溢出),则取0
{
if (lib[left] * 5 < 2119458569)
lib[k++] = lib[left] * 5;
else
lib[k++] = 0;
}
n++;
}
// printf("\nk = %d\n", k);
qsort(lib, k, sizeof(unsigned long), Compare);//非递增排列
k = Move(lib, k); //去掉数值为0的元素
// printf("\nk = %d\n", k);
//int j;
// for (j=0; j<k; j++)
// printf("%ld\t", lib[j]);
unsigned int data[MAX] = {0};
int temp;
scanf("%d", &temp);
int len = 0;
while (temp != 0)
{
data[len++] = temp;
scanf("%d", &temp);
}
int i;
for (i=0; i<len; i++)
printf("%d\n", lib[data[i]-1]);
system("pause");
return 0;
}
int Move(unsigned long lib[], int len)
{
int i = 0;
while (lib[i] == 0)
i++;
int j = 0;
while (i < len)
lib[j++] = lib[i++];
return j;
}
4 楼
goal00001111 [专家分:4030] 发布于 2006-11-11 13:55:00
一点疑惑:结果似乎有问题,但尚未找到原因----找到了,原来是k的上限设置太小了,增大上限后就正确了.
修改的代码如下:unsigned long max = MAX*2;
while (k < max)
5 楼
hikederen [专家分:10] 发布于 2006-11-19 22:28:00
我不懂英文能把这道题贴出来吗
我来回复