poj1840

这个题目的意思很简单就是给定一个五元三次方程ax1^3+bx2^3+cx3^3+dx4^4+ex5^5=0,并每次给定系数a,b,c,d,e,系数的范围和变量xi,i为[1,5]的范围均在[-50,50],并且变量的值均不为0,由于在[-50,50]的范围内,函数x^3是单调递增的,故这里可将x^3与x一一对应起来。那么五元三次方程实际上可以转化为五元一次方程。即ax1+bx2+cx3+dx4+ex5=0形式。其中xi的取值为上述xi^3,最朴素的算法就是枚举了,但是5个for循环,时间复杂度为O(100^5),计算机每毫秒大约运行1000次,那么5000ms运行500M次,所以一定会超时。然后我猜想能否利用几何特征优化枚举。即将方程进一步转化为这样的形式:ax1+bx2+cx3=-dx4-ex5。这样左边表示一个平面,右边表示一个直线。但是我又发现这里实际上存在5个不同的变量,不可能用三维坐标,要建立五维坐标,三维以上的坐标系将非常麻烦,故果断放弃这种想法。但是可以转化为ax1^3+bx2^3+cx3^3=-dx4^3-ex5^3,利用哈希查找的方式优化枚举,我先将方程右边的式子的值打表存放,然后枚举左边的式子,对于左边每一种计算的可能,判断哈希位置在哈希表中是否存在,若不存在,则说明右边所有式子的可能取值中没有一个与其相等。若存在,则说明在该右边式子所有可能的取值中只有在该哈希位置的值才可能与其相等。接下来就是逐个比较,若相等则count++,其中count为记录方程所有可能解的个数。否则比较下一个。

这里注意四个问题:

1)将右边式子的值打表存放时,这里将右边式子的值的绝对值作为key(左边同理),因为考虑到有可能存在负数的情况。

2)哈希表中存放的是右边式子的真实值,并且对于右边式子的所有可能取值都要存放在哈希表中,防止后续比较时遗漏解空间。(即99×99种取值都要存放在哈希表中,即使是相同的)

3)这里用int存放左边式子和右边式子的值,因为int类型数据的范围较-100000000到100000000大,故可以很放心的记录左边式子和右边式子的值。而记录解空间个数变量count要为__int64存放,因为最大的可能取值为100^5超过了int类型的取值范围。并且取右边式子可能取值的不同情况100×100的10倍范围内的最大素数值为哈希表的长度。

4)取方程右边两个,左边三个变量是有意义的,从时间和空间的角度

下面是代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define Max 99991
struct Node{
	int value;
	struct Node *next;
}node[Max];
bool trag[Max];
int a,b,c,d,e;
__int64 count=0;
void Hash(bool flag,int key){
	int temp=abs(key)%Max;
	if(!flag){
		if(!trag[temp]){
			trag[temp]=1;
			node[temp].value=key;
			node[temp].next=NULL;
		}
		else{
			struct Node *pivot=(struct Node *)malloc(sizeof(struct Node));
			pivot->value=key;
			pivot->next=node[temp].next;
			node[temp].next=pivot;
		}
	}
	else{
		if(trag[temp]){
			struct Node *pivot=&node[temp];
			while(pivot!=NULL){
				if(pivot->value==key)
					count++;
				pivot=pivot->next;
			}
		}
	}
}
int main(){
	scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);
	int x1,x2,x3,x4,x5;
	memset(trag,0,sizeof(trag));
	for(x1=-50;x1<=50;x1++){
		if(x1==0)
			continue;
		for(x2=-50;x2<=50;x2++){
			if(x2==0)
				continue;
			Hash(0,-1*a*x1*x1*x1-b*x2*x2*x2);
		}
	}
	for(x3=-50;x3<=50;x3++){
		if(x3==0)
			continue;
		for(x4=-50;x4<=50;x4++){
			if(x4==0)
				continue;
			for(x5=-50;x5<=50;x5++){
				if(x5==0)
					continue;
				Hash(1,c*x3*x3*x3+d*x4*x4*x4+e*x5*x5*x5);
			}
		}
	}
	printf("%d\n",count);
	return 0;
}		


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值