zoukankan      html  css  js  c++  java
  • [PAT] A1103 Integer Factorization

    (dfs深度优先搜索)

    思路

    先把i从0开始所有的i的p次方的值存储在v[i]中,直到v[i] > n为止。(如果在递归过程中计算次方,会做很多重复工作,很浪费时间。)
    然后深度优先搜索,记录当前正在相加的index(即v[i]的i的值),当前的总和tempSum,当前K的总个数tempK,以及因为题目中要求输出因子的和最大的那个,所以保存一个facSum为当前因子的和,让它和maxFacSum比较,如果比maxFacSum大就更新maxFacSum和要求的ans数组的值。
    在ans数组里面存储因子的序列,tempAns为当前深度优先遍历而来的序列,从v[i]的最后一个index开始一直到index == 1,因为这样才能保证ans和tempAns数组里面保存的是从大到小的因子的顺序。
    一开始maxFacSum == -1,如果dfs后maxFacSum并没有被更新,还是-1,那么就输出Impossible,否则输出答案。
    剪枝:
    1.tempK==K但是tempSum!=n的时候需要剪枝
    2.在枚举的时候,按顺序枚举,上界或者下界可进行剪枝
    3.当且仅当tempSum + v[index] <= n时,进行下一层的DFS,而不要进入下一层DFS发现不满足条件再返回,这样开销会比较大
    4.每次temv的push_back、pop_back都需要重新分配内存空间,比较耗时,由于答案的序列长度是确定的,可以将ans序列初始化为定长的,这样在递归的过程中就不需要push、pop; pow的计算结果可以保存下来,以免重复计算,耗用多余的时间

    1.要先存好次方计算后的值,避免递归时重复计算。
    2.直接利用maxsum来判断是否有解,通过设初值为负数。无需额外建立标记判断。
    3.倒着递归,从大数开始判断。

    AC代码

    /*第二次写*/
    #define _CRT_SECURE_NO_WARNINGS
    #include<iostream>
    #include<math.h>
    #include<vector>
    using namespace std;
    int n, k, p, maxsum = -1;
    vector<int>num, ans, bestans;
    void DFS(int index, int result, int sum, int x) {
    	if (result == n && x == k) {
    		if (sum > maxsum) {
    			bestans = ans;
    			maxsum = sum;
    		}
    		else if (sum == maxsum) {
    			int i = k - 1;
    			while (i >= 0 && ans[i] == bestans[i])i--;
    			if (ans[i] > bestans[i])bestans = ans;
    		}
    		return;
    	}
    	else if (index < 0 || x >= k || result >= n)return;
    	if (result + num[index] <= n) {
    		ans[x] = index + 1;
    		DFS(index, result + num[index], sum + index, x + 1);
    	}
    	DFS(index - 1, result, sum, x);
    }
    
    int main() {
    	int i, a, b;
    	scanf("%d%d%d", &n, &k, &p);
    	ans.resize(k); bestans.resize(k);
    	for (i = 1; i <= n; i++) {
    		a = pow(i, p);	
    		if (a > n)break;
    		num.push_back(a);
    	}
    	DFS(num.size() - 1, 0, 0, 0);
    	if (maxsum < 0)printf("Impossible");
    	else {
    		printf("%d = %d^%d", n, bestans[0], p);
    		for (i = 1; i < k; i++)printf(" + %d^%d", bestans[i], p);
    	}
    	return 0;
    }
    
    #define _CRT_SECURE_NO_WARNINGS
    #include<cstdio>
    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define MAX 500
    int n, k, p, maxsum = -1;
    vector<int>v;
    vector<int>solution, maxsolution;
    void optmax() {
    	int i = 0;
    	while (solution[i] == maxsolution[i])i++;
    	if (solution[i] > maxsolution[i])
    		maxsolution = solution;
    }
    void DFS(int index, int count, int ans, int sum) {
    	if (count == k && ans == n) {
    		if (maxsum < sum) {
    			maxsum = sum;
    			maxsolution = solution;
    		}
    		else if (maxsum == sum) optmax();  //此处可以不用判断相等情况,也能AC。
    		return;
    	}
    	if (index == 0 || ans > n || count >= k)return;
    	if (ans + v[index] <= n) {
    		solution.push_back(index);
    		DFS(index, count + 1, ans + v[index], sum + index);
    		solution.pop_back();
    	}
    	DFS(index - 1, count, ans, sum);
    }
    int main() {
    	scanf("%d%d%d", &n, &k, &p);
    	int temp = 0, index = 1;
    	while (temp <= n) {
    		v.push_back(temp);
    		temp = pow(index, p);
    		index++;
    	}
    	DFS(v.size() - 1, 0, 0, 0);
    	if (maxsum < 0)printf("Impossible");
    	else {
    		printf("%d = %d^%d", n, maxsolution[0], p);
    		for (int i = 1; i < k; i++)
    			printf(" + %d^%d", maxsolution[i], p);
    	}
    	return 0;
    }
    

    如果改成正着来,测试点5就超时了...实在想不通是什么回事,希望走过路过的大神们帮我看看,感激不尽!!!
    (我想应该是从大数开始比较容易到达边界,减少了递归次数)

    #define _CRT_SECURE_NO_WARNINGS
    #include<cstdio>
    #include<iostream>
    #include<vector>
    #include<map>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define MAX 500
    int n, k, p, maxsum = -1;
    vector<int>v;
    vector<int>solution, maxsolution;
    bool cmp(int a, int b) { return a > b; }
    void optmax() {
    	int i = 0;
    	while (solution[i] == maxsolution[i])i++;
    	if (solution[i] > maxsolution[i])
    		maxsolution = solution;
    }
    void DFS(int index, int count, int ans, int sum) {
    	if (count == k && ans == n) {
    		if (maxsum < sum) {
    			maxsum = sum;
    			maxsolution = solution;
    		}
    		else if (maxsum == sum) optmax();
    		return;
    	}
    	if (index >= v.size() || ans > n || count >= k)return;
    	if (ans + index <= n) {
    		solution[count] = index;
    		DFS(index, count + 1, ans + v[index], sum + index);
    	}
    	DFS(index + 1, count, ans, sum);
    }
    int main() {
    	scanf("%d%d%d", &n, &k, &p);
    	solution.resize(k);
    	int temp = 0, index = 1;
    	while (temp <= n) {
    		v.push_back(temp);
    		temp = pow(index, p);
    		index++;
    	}
    	DFS(1, 0, 0, 0);
    	if (maxsum < 0)printf("Impossible");
    	else {
    		printf("%d = %d^%d", n, maxsolution[k - 1], p);
    		for (int i = k - 2; i >= 0; i--)
    			printf(" + %d^%d", maxsolution[i], p);
    	}
    	return 0;
    }
    
  • 相关阅读:
    USACO 3.3 A Game
    USACO 3.3 Camelot
    USACO 3.3 Shopping Offers
    USACO 3.3 TEXT Eulerian Tour中的Cows on Parade一点理解
    USACO 3.3 Riding the Fences
    USACO 3.2 Magic Squares
    USACO 3.2 Stringsobits
    USACO 3.2 Factorials
    USACO 3.2 Contact
    USACO 3.1 Humble Numbers
  • 原文地址:https://www.cnblogs.com/yue36/p/13346039.html
Copyright © 2011-2022 走看看