8.1 深度优先搜索(DFS)

2019年9月PAT - 练习笔记——8.1

以下页码标注的是阅读器中实际页码,而不是书本身自印的页码。

第8章 提高篇(2)——搜索专题

8.1 深度优先搜索(DFS)

注意

  1. 可以考虑对某些数据进行预处理,从而提高效率

目录

  1. A1103 Integer Factorization

  1. A1103 Integer Factorization

    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
    
    1. 我的

      #include <iostream>
      #include <cmath>
      #include <vector>
      
      using namespace std;
      
      int n = 0, k = 0, p = 0;
      int nowSum = 0;
      vector<int> factors, sequences;
      bool flag = false;
      void Find(int now, int sum)
      {
      	if (now == k) {
      		if (sum == n) {
      			if (sequences.empty()) {
      				sequences = factors;
      				for (int i = 0;i < k;++i) nowSum += factors[i];
      			}
      			else {
      				int tmp = 0;
      				for (int i = 0;i < k;++i) tmp += factors[i];
      				if (tmp > nowSum) {
      					nowSum = tmp;
      					sequences = factors;
      				}
      				else if (tmp == nowSum && factors > sequences) sequences = factors;
      			}
      			flag = true;
      		}
      		return;
      	}
      	for (;factors[now] <= factors[now - 1];++factors[now]){
      		int tmp = sum + pow(factors[now], p);
      		if (tmp <= n) Find(now + 1, tmp);
      	}
      	factors[now] = 1;
      }
      
      int main(void)
      {
      	scanf("%d %d %d", &n, &k, &p);
      	factors.resize(k, 1);
      	
      	factors[0] = pow(n - (k - 1), 1 / (float)p);
      	int end = pow((float)n / k, 1 / (float)p);
      	for (;factors[0] >= end;--factors[0]) Find(1, pow(factors[0], p));
      	if (!flag) printf("Impossible");
      	else {
      		printf("%d = %d^%d", n, sequences[0], p);
      		for (int i = 1;i < k;++i) printf(" + %d^%d", sequences[i], p);
      	}
      	
      	return 0;
      }
      

      这题我记得当初写了好久……这次提交一遍过!超级开心!

      但我的算法不是很好,参考代码写的比较好

    2. 《算法笔记》P286

      1. “由于P不小于2,并且在单次运算中是固定的,因此不妨开设一个vector fac,在读入P之后就预处理所有不超过N的np。为了方便下标与元素有直接的对应,这里应把0也存进去。于是对N = 10、P = 2来说,fac[0] = 0, fac[1] = 1, fac[2] = 4, fac[3] = 9。”

      2. “为了让结果能保证字典序大的序列优先被选中,让index从大到小递减来遍历,这样就总是能先选中fac中较大的数了。

        显然,如果当前需要对fac[index]进行选择,那么就会有“选”与“不选”两种选择。如果不选,就可以把问题转化为对fac[index - 1]进行选择……而如果选,由于每个数字可以重复选择,因此下一步还应当对fac[index]进行选择……”

      #include <cstdio>
      #include <vector>
      #include <algorithm>
      
      using namespace std;
      
      int n, k, p, maxFacSum = -1;
      vector<int> fac, ans, temp;
      
      int power(int x) 
      {
      	int ans = 1;
      	for (int i = 0;i < p;i++) ans *= x;
      	return ans;
      }
      void init()
      {
      	int i = 0, temp = 0;
      	while (temp <= n) {
      		fac.push_back(temp);
      		temp = power(++i);
      	}
      }
      void DFS (int index, int nowK, int sum, int facSum)
      {
      	if (sum == n && nowK == k) {
      		if (facSum > maxFacSum) {
      			ans = temp;
      			maxFacSum = facSum;
      		}
      		return;
      	}
      	if (sum > n || nowK > k) return;
      	if (index - 1 >= 0) {
      		temp.push_back(index);
      		DFS(index, nowK + 1, sum + fac[index], facSum + index);	// "选"的分支
      		temp.pop_back();
      		DFS(index - 1, nowK, sum, facSum);	// “不选”的分支
      	}
      }
      
      int main()
      {
      	scanf("%d%d%d", &n, &k, &p);
      	init();
      	DFS(fac.size() - 1, 0, 0, 0);
      	if (maxFacSum == -1) printf("Impossible\n");
      	else {
      		printf("%d = %d^%d", n, ans[0], p);
      		for (int i = 1;i < ans.size();i++) printf(" + %d^%d", ans[i], p);
      	}
      	return 0;
      }
      
上一篇:一个数如果恰好等于不包含它本身所有因子之和,这个数就称为"完数"。 例如,6的因子为1、2、3,而6=1+2+3,因此6是"完数"。 编程序找出N之内的所有完数


下一篇:(C#版)使用TCC分布式事务改造现有下单流程(二)