PAT A1103 Integer Factorization (!難***DFS)

問題鏈接:https://pintia.cn/problem-sets/994805342720868352/problems/994805364711604224

題意:

    給定正整數N, K, P,將N表示成K個正整數(可以相同,遞減排序)的P次方的和,即N = n1^P+...nk^p。如果有多種方案,那麼選擇底數和n1+n2+...nk最大的方案;如果還有多種方案,那麼選擇底數序列的字典序最大的方案。

思路:

  1.     由於P大於1,並且在單詞運行中是固定的,因此開一個vector<int> fac,在輸入P之後就預處理出所有不超過N的n的P次方。即對N= 10,P = 2來說,fac[0] = 0, fac[1] = 1, fac[2] = 4, fac[3]=9...
  2.     DFS函數用於從fac中選擇若干個數(可以重複選),使得它們的和等於N。於是需要針對fac中的每個數,根據選與不選這個數來進入兩個分支,因此DFS的參數中必須有:(1)當前處理到的是fac的幾號位,記爲index;(2)當前已經選擇了幾個數,記爲nowK。(3)當前選擇出的數之和sum。(4)爲了保證有多個方案時底數之和最小,還需在參數中記錄當前選擇出的數的底數之和facSum。————另外開一個vector<int> ans,用來存放最優的底數序列,用一個vector<int> temp存放當前選中的底數組成的臨時序列
  3. 爲讓結果能保證字典序大的序列優先被選中,讓index從大到小遞減來遍歷,這樣就總是能選中fac中較大的數
#include<cstdio> 
#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;

vector<int> fac, ans, temp;
int N, K, P, maxfacsum = 0;//maxfacsum記錄最大底數之和 

//預處理fac數組 
void init(){
	int i = 1, temp = 0;
	while(temp <= N){//當i的P次方沒有超過n時,不斷把i的P次方加入fac 
		fac.push_back(temp);
		temp = pow(i, P);
		i++;
	}
}

//DFS函數,當前訪問fac[index],nowK爲當前選中個數
//sum爲當前選中的數之和,facsum爲當前選中的底數之和 
void DFS(int index, int nowK, int sum, int facsum){
	if(nowK == K && sum == N){
		if(facsum > maxfacsum){
			ans = temp;//更新最優底數序列,vector容器之間賦值
			maxfacsum = facsum;//更新最大底數和 
		}
		return;
	}
	if(sum > N || nowK > K)
	    return;
	if(index - 1 >= 0){//fac[0]不需要選擇 
		temp.push_back(index);//把底數index加入臨時序列temp
		DFS(index, nowK + 1, sum + fac[index], facsum + index);//選的分支 
		temp.pop_back();//選的分支結束把剛加進去的數pop掉
		DFS(index - 1, nowK, sum, facsum); //不選的分支 
	}
}
	
int main(){
	cin >> N >> K >> P;
	init();
	DFS(fac.size() - 1, 0, 0, 0);
	if(maxfacsum == 0)
	    cout << "Impossible"<<endl;
	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;
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章