PAT 甲级 1103 Integer Factorization (30 分)

这题的测试点5从一直超时,然后慢慢改到400ms再改到200ms+,再到现在10几ms,真辛酸啊。。

思路:

1.基本想法就是枚举,暴力解,最开始用的循环做的枚举,后来发现利用递归去做更容易实现剪枝;
2.将[1,n-k+1]区间的整数的p-1次方用数组存储起来,将[1,(n-k+1)1/p]区间的整数的p次方用数组存储起来,以免之后用到时反复计算;
3.然后从下标1到k开始dfs,记录此次递归的下标index、历史次方和facSum、前一个数的大小last、历史算术和calSum,我们记up=max{(n-facSum-k+index)1/p,last},则下标为index的数,我们就应该从up遍历到1;
4.我们使用两个vector分别记录当前的测试数据和我们历史最佳结果,用sum记录历史最佳结果的算术和,若此次的测试结果按规则比历史最佳结果要好,则进行替换;
5.因为后面的数永远小于等于前面的数,因此若遍历到下标为index且index取值为i时,这趟遍历算术和最大的结果就是从index往后数字全为i,则和为(k-index+1)*i+calSum,如果它小于sum,那我们就进行剪枝,直接结束此趟遍历;

代码:

#include<iostream>
#include<cmath>
#include<vector>
using namespace std;
int n,k,p,sum=0;
vector<int> rv(1,0),v(1,0),rs,test;
void cmp(int calSum){
	if(calSum>sum){
		rs=test;
		sum=calSum;
	}
	else{
		for(int i=1;i<=k;i++)
			if(test[i]<rs[i]) return;
			else if(test[i]>rs[i]){
				rs=test;
				return;
			}
	}
}
void dfs(int index,int facSum,int last,int calSum){
	int up=rv[n-facSum-k+index];
	up=up>last?last:up;
	for(int i=up;i>0;i--){
		test[index]=i;
		if(sum!=0&&(k-index+1)*i+calSum<sum) return;
		if(index!=k) dfs(index+1,facSum+v[i],i,calSum+i);
		else if(facSum+v[i]==n) cmp(i+calSum);
	}	
}
int main(){	
	scanf("%d%d%d",&n,&k,&p);
	double rp=pow(p,-1);
	rs.resize(k+1);
	test.resize(k+1);
	for(int i=1;i<=n-k+1;i++) rv.push_back(pow(i,rp));
	for(int i=1;i<=rv[n-k+1];i++) v.push_back(pow(i,p));
	dfs(1,0,rv[n-k+1],0);
	if(rs[1]==0) printf("Impossible");
	else{
		printf("%d = %d^%d",n,rs[1],p);
		for(int i=2;i<=k;i++) printf(" + %d^%d",rs[i],p);
	}
	return 0;
}
posted @ 2019-09-01 14:39  YuhanのBlog  阅读(90)  评论(0编辑  收藏  举报