PAT Advanced 1103 Integer Factorization (30) [深度优先搜索DFS]

题目

The K-P factorization of a positive integer N is to write N as the sum of the P-th power of K positive integers. You are supposed to write a program to find the K-P factorization of N for any positive integers N, K and P.
Input Specification:
Each input file contains one test case which gives in a line the three positive integers N (<=400), K (<=N) and P (1<P<=7). The numbers in a line are separated by a space.
Output Specification:
For each case, if the solution exists, output in the format:
N = n[1]^P + … n[K]^P
where ni (i=1, … K) is the i-th factor. All the factors must be printed in non-increasing order. Note: the solution may not be unique. For example, the 5-2 factorization of 169 has 9 solutions, such as 12^2 + 4^2 + 2^2 + 2^2 + 1^2, or 11^2 + 6^2 + 2^2 + 2^2 + 2^2, or more. You must output the one with the maximum sum of the factors. If there is a tie, the largest factor sequence must be chosen — sequence { a1, a2, … aK} is said to be larger than { b1, b2, … bK } if there exists 1<=L<=K such that ai=bi for ibL If there is no solution, simple output “Impossible”.
Sample Input 1:
169 5 2
Sample Output 1:
169 = 6^2 + 6^2 + 6^2 + 6^2 + 5^2
Sample Input 2:
169 167 3
Sample Output 2:
Impossible

题目分析

已知N,求k个p次幂的数之和=N
若有多个序列,取底数和最大的序列;若仍有多个序列,取大序列(两个序列,前i项都相等,第i+1项较大者)
输出要求:序列中数字非升序排列

解题思路

  1. 因为p不变,可以预处理将所有p次方结果<=n的数字保存于容器(若某个数的p次方大于n,那么这个数字不可能被选中)
  2. dfs深度搜索,从大数字到小数字遍历,被选中数字可以重复再次被选中,所以当前数字有两种支路:当前数字被选择并记录;当前数字不被选择跳过选择下个数字
  3. dfs退出条件:
    3.1 (无效序列)已被选中的数字之和大于n
    3.2 (无效序列)已被选中的数字个数大于k
    3.3 (有效序列)已被选中的数字之和等于n并且已被选中的数字个数等于k,更新最优解

Code

#include <iostream>
#include <vector>
using namespace std;
int n,k,p,maxSum;
vector<int> fac,ans,temp;
int power(int x) {
	// 方法一:p个x相乘
	int ans =1;
	for(int i=0; i<p; i++)
		ans*=x;
	return ans;
	//方法二:使用cmath中power函数
}
void init() {
	for(int i=0; power(i)<=n; i++)
		fac.push_back(power(i));
}
// index 当前访问的索引
// numK 当前已经选择的数字个数
// sum 当前已经选择的数字之和
// facnum 当前已经选中的数字底数之和
void dfs(int index, int numK,int sum,int facSum) {
	if(sum==n&&numK==k) {
		// 符合条件,更新最优解
		if(facSum>maxSum) {
			ans=temp; //保存序列
			maxSum=facSum; //更新底数和最大值
		}
		return;
	}
	if(sum>n||numK>k)return;
	if(index>=1) { //不选0
		temp.push_back(index);
		dfs(index, numK+1, sum+fac[index], facSum+index); //选择当前数字
		temp.pop_back();
		dfs(index-1, numK, sum, facSum); //不选择当前数字
	}
}
int main(int argc,char *argv[]) {
	scanf("%d %d %d",&n,&k,&p);
	init(); //预处理数字的固定幂次结果 
	dfs(fac.size()-1,0,0,0);
	if(ans.empty()) printf("Impossible");
	else {
		printf("%d = %d^%d",n, ans[0], p);
		for(int i=1; i<k; i++)
			printf(" + %d^%d", ans[i], p);
	}
	return 0;
}

Code 2

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=410;
int n,k,p,pw[maxn],maxi,maxfacsum=-1;
vector<int> ans,temp;
void initial(int v) {
	for(int i=0; pow(i,p)<=v; i++) {
		pw[i]=pow(i,p);
		maxi = i;
	}
}
void dfs(int index,int tempsum,int tempk,int facsum) {
	if(tempk==k) {
		if(tempsum==n&&facsum>maxfacsum) {
			maxfacsum=facsum;
			ans=temp;
		}
		return;
	}
//	while(index>=1){
//		if(tempsum+pw[index]<=n){
//			temp[tempk]=index;
//			dfs(index,tempsum+pw[index],tempk+1,facsum+index);
//		}
////		if(index==1)return;
//		index--;
//	}
	for(int i=index; i>=1; i--) {
		if(tempsum+pw[i]<=n) {
			temp[tempk]=i;
			dfs(i,tempsum+pw[i],tempk+1,facsum+i);
		}
	}

}
int main(int argc,char * argv[]) {
	scanf("%d%d%d",&n,&k,&p);
	initial(n);
	temp.resize(k);
	dfs(maxi,0,0,0);
	if(maxfacsum==-1) {
		printf("Impossible");
		return 0;
	}
	printf("%d =",n);
	for(int i=0; i<ans.size(); i++) {
		if(i!=0)printf(" +");
		printf(" %d^%d",ans[i],p);
	}
	return 0;
}



posted @ 2020-03-23 22:53  JamieHou  阅读(112)  评论(0编辑  收藏  举报