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;
    }
    
  • 相关阅读:
    mySQL优化方案
    java之自动过滤提交文本中的html代码script代码
    java小技术之生成二维码
    微信扫码支付功能详细教程————Java
    java实现发送邮件服务器,SMTP协议发送邮件
    『重构--改善既有代码的设计』读书笔记----序
    Linux导航神器-----autojump
    绘图时,根据size()和自定义rect编程的区别
    Qt中如何在QCursor移动的时候不触发moveEvent
    Qt远程机开发时光标注意问题
  • 原文地址:https://www.cnblogs.com/yue36/p/13346039.html
Copyright © 2011-2022 走看看