1103. Integer Factorization (30)-PAT甲级真题 (剪枝)

题意

给定目标数字n、组成数量k、次方数p,要求得到k个数字a[1]...a[k]满足a[i] >= a[j](i < j) n = a [ 1 ] p + . . . + a [ k ] p n = a[1]^p + ... + a[k]^p n=a[1]p+...+a[k]p 如果有tie,则取sum = a[1] + ... + a[k]最小值对应解,如果仍有tie,则取vector<int> ans最小解。

思路

首先很自然想到用DFS,但是顺手写下来就TLE了,管上限 测试点5 TLE,管下限 测试点0 TLE。

分析原因1

p最大 = 7,为了避免重复求pow(a, p),在DFS前算好要用的因子存到fact[idx],这样最多O(n) /= 7;

int fact[23], idx = 1;
while(fact[idx - 1] < n) fact[idx++] = pow(idx, p);

分析原因2

每次取因子进入tmp数组时,有些因子没必要考虑。

  • 比如从1 - ptr中,对于pow(ptr1, p) * k < n的,不用进入下层循环,于是成了[ptr1 + 1, ptr]
  • 比如对于pow(ptr2, p) > n - k + 1的,当进入下层循环后, n n e x t = n − p o w ( p t r 2 , p ) < k − 1 n_{next} = n - pow(ptr2, p) < k - 1 nnext=npow(ptr2,p)<k1 不能凑出剩下k - 1个数字,也不用进入下层循环。于是简化成了[ptr1 + 1, ptr2 - 1]
while(ptr > 0){
	if(fact[ptr] * k < n)break;
	if(n - k + 1 >= fact[ptr]){
		tmp.push_back(ptr);
		DFS(n - fact[ptr], k - 1, sum + ptr, ptr);
		tmp.pop_back();
	}
	ptr--;
}

分析原因3

每次找到目标后,对比此前找到的目标ans,和当前找到的目标tmp的过程需要O(k),而k有可能比较大。
常规比较方法:

int sum1 = 0, sum2 = 0;
for(int i = 0; i < k; i ++) sum1 += ans[i], sum2 += tmp[i];
if(sum1 < sum2) ans = tmp;
else if(sum1 == sum2){
	int i = 0;
	while(i < ans.size() && ans[i] == tmp[i]) i++;
	if(i < ans.size() && tmp[i] > ans[i]) ans = tmp;
}

观察不难想到sum是不用重复求,用DFS传参进入下层循环即可。
那对比ans与tmp呢?不难发现在dfs过程中,同层元素要么从小到大,要么从大到小,假设从大到小,则每次第一次修改max_sum时对应的最优解。反之最后,代码如下:

if(k == 0){
	if(max_sum < sum){
		max_sum = sum;
		ans = tmp;
	}
	return;
}

总结 - 剪枝

  • 对于DFS,同一层往往有一个顺序,如此题可以是顺序取[ptr, 1]到下一层DFS(n - fact[ptr], k - 1, sum + ptr, ptr);
  • 然后对如上所取的两边进行剪枝,剪枝方法是看目标ptr与其他参数之间的约束关系,比如此题用n、k和ptr的关系,从[ptr, 1]剪枝到[ptr2, ptr1]
  • 为了方便理解逻辑,可以简单枚举前几层DFS的参数以观察规律,这里不难发现最有规律的是k,每下一层k–,并且约束着n不会成为负数,于是出循环条件为if(k == 0) return;

题解1

#include<bits/stdc++.h>
using namespace std;
int fact[23], idx = 1, n, k, p, max_sum;
vector<int> tmp, ans;
void DFS(int n, int k, int sum, int ptr){
    if(k == 0){
        if(max_sum < sum){
            max_sum = sum;
            ans = tmp;
        }
        return;
    }
    while(ptr > 0){
        if(fact[ptr] * k < n)break;
        if(n - k + 1 >= fact[ptr]){
            tmp.push_back(ptr);
            DFS(n - fact[ptr], k - 1, sum + ptr, ptr);
            tmp.pop_back();
        }
        ptr--;
    }
}
int main(){
    cin>>n>>k>>p;
    while(fact[idx - 1] < n) fact[idx++] = pow(idx, p);
    DFS(n, k, 0, idx - 1);
    if(!max_sum) puts("Impossible");
    else{
        printf("%d = ", n);
        for(int i = 0 ; i < k ; i++)
            printf("%d^%d%s", ans[i], p, i == k - 1 ? "\n" : " + ");
    }
    return 0;
}

题解2(从小到大找因子,结果一样20ms过测试点5)

#include<bits/stdc++.h>
using namespace std;
int fact[23], idx = 1, n, k, p, max_sum;
vector<int> tmp, ans;
void DFS(int n, int k, int sum, int ptr){
    if(k == 0){
        if(max_sum <= sum) max_sum = sum, ans = tmp;
        return;
    }
    for(int i = 1; i <= ptr; i++){
        if(fact[i] * k < n) continue;
        else if(n - fact[i] >= k - 1){
            tmp.push_back(i);
            DFS(n - fact[i], k - 1, sum + i, i);
            tmp.pop_back();
        }else break;
    }
}
int main(){
    cin>>n>>k>>p;
    while(fact[idx - 1] < n) fact[idx++] = pow(idx, p);
    DFS(n, k, 0, idx - 1);
    if(!max_sum) puts("Impossible");
    else{
        printf("%d = ", n);
        for(int i = 0 ; i < k ; i++)
            printf("%d^%d%s", ans[i], p, i == k - 1 ? "\n" : " + ");
    }
    return 0;
}

题目

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 n[i] (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 122+42+22+22+12, or 112+62+22+22+22, 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 i<L and aL​>bL​.

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值