hdu5902暴力

传送门:hdu5902

题意还比较简单,就是做的时候有点懵逼,既然它让求任意三个数的gcd,因为数据量较小就可以遍历,每两个数取一次gcd,将gcd用数组标记出来,因为题中说明还要再把取出来的三个数的最大gcd放回去,假设某一次放回去的为a,a,下一次取出来的为a,a,x,此处x为任意的输入的数,(这里可能会有疑问说如果取得三个数都是之前求得的gcd呢,假设取出来的x,y,z,都是之前求得的gcd,假设放回去的gcd “m"是由x,y求得的,那么就相当于x和求得y的两个数(p,q)再加上z做了两次gcd(x,p,z)和(x,q,z)求得m,这样回溯到底就相当于括号外面的做法)则再放回去的可能为gcd(a,a)或者gcd(a,x),所以每一次产生了新的gcd后就要将被标记出来的数(上几步求出来的gcd)和输入的数重新做一遍gcd,最后没有新的gcd了就停止,最后输出的时候再注意一下格式就行了。

这样做的缺点是时间复杂度很高,在本题中数据量小还可以,不过也达到了795MS,数据量稍微大一点的话就很难了,希望大神能有更好的解法。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int gcd(int n,int m)//辗转相除求最大公约数 
{
	int r;
	while(m)
	{
		r=n%m;
		n=m;
		m=r;
	}
	return n;
}
int num[505],book[1001];
int main()
{
	int t,n;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			scanf("%d",&num[i]);
		}
		memset(book,0,sizeof(book));
		for(int i=0;i<n-1;i++)//两两求gcd 
		for(int j=i+1;j<n;j++)
		{
			book[gcd(num[i],num[j])]=1;
		}
		int flag=1;//标记是否有新的gcd产生 
		int len=1;
		while(flag&&len<n-2)
		{
			flag=0;
			len++;
			for(int i=1;i<=1000;i++)//将之前求出来的gcd和输入的数两两取再gcd 
			for(int j=0;j<n;j++)
			{
				if(book[i]&&!book[gcd(i,num[j])])
				{
					flag=1;
					book[gcd(i,num[j])]=1;
				}
			}
		}
		flag=1;
		for(int i=0;i<=1000;i++)//输出注意格式 
		{
			if(book[i])
			{
				if(flag)
				{
					printf("%d",i);
					flag=0;
				}
				else
				printf(" %d",i);
			}
			
		}
		putchar('\n');
	}
return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值