• 部分和问题---多重部分和问题---动态规划


    第一:01部分和(每个数只取一次)

    给定整数a1、a2、.......an,判断是否可以从中选出若干数,使它们的和恰好为K。
    输入:
    n=4
    a={1,2,4,7}
    k=13
    输出:
    Yes(13=2+4+7)
    思路:先介绍一种深度优先的搜索方法,从a1顺序决定每个数加或不加,在全部n个数都决定之后在判断和是否为K即可。这个搜索的复杂度是O(2^n).
    int a[MAXN];
    int n,k;
    
    bool dfs(int i,int sum){
        if(i==n) return sum==k;
        if(dfs(i+1,sum))return 1;
        if(dfs(i+1,sum+a[i]))return 1;
       return 0;
    }
    
    /// initial call dfs(0,0);

    如果要求保存相加的每一个数,可以这样实现:
    #include <iostream>
    #include <vector>
    using namespace std;
    int a[4]={1,2,4,7},k;
    vector<int> ans;
    void dfs(int i,int sum)
    {
    	if(i==4){
    		if(sum==k)
    	   	{
       			for(int i=0;i!=ans.size();i++)cout<<ans[i]<<" ";
    			cout<<endl;
    			return ;
       		}
       		else 
    		 return ;
    	}
    	dfs(i+1,sum);
    	ans.push_back(a[i]);
    	dfs(i+1,sum+a[i]);
    	ans.pop_back();
    	return ;
    }
    int main()
    {
    	 k=7;
    	 dfs(0,0);
    }

    第二:多重部分和

    n种大小不同的数字 ai,每种各mi个,判断是否可以从这些数字之中选出若干个使他们的和恰好为K。
    输入:
    n=3;
    a={3,5,8}
    m={3,2,2}
    K=17
    输出:
    Yes(3*3+8)
    思路:
    这个问题可以用DP来求解: dp[i][j] := 用前i种数字是否能加和成j
    #include <iostream>
    #include <vector>
    using namespace std;
    int n,K;
    const int maxn=100;
    const int maxk=100000;
    int a[maxn],m[maxn];
    bool dp[maxn][maxk];
    int main()
    {
    	cin>>n;
    	for(int i=0;i<n;i++)
    		cin>>a[i];
    	for(int i=0;i<n;i++)
    		cin>>m[i];
    	cin>>K;
    	dp[0][0]=1;
    	for(int i=0;i<n;i++)
    		for(int j=0;j<=K;j++)
    			for(int k=0;k<=m[i] && k*a[i]<=j;k++){
    				dp[i+1][j] |=dp[i][j-k*a[i]];
    			}
    	
    	if(dp[n][K])cout<<"yes"<<endl;
    	else cout<<"no"<<endl;
    	//cout<<dp[n][K]<<endl;
    	return 0;				
    }

    将这个问题稍加变形:求解从这些数字中选取若干能恰好加和成K的方法数。
    #include <iostream>
    #include <vector>
    using namespace std;
    int n,K;
    const int maxn=100;
    const int maxk=100000;
    int a[maxn],m[maxn];
    int dp[maxn][maxk];
    int main()
    {
    	cin>>n;
    	for(int i=0;i<n;i++)
    		cin>>a[i];
    	for(int i=0;i<n;i++)
    		cin>>m[i];
    	cin>>K;
    	dp[0][0]=1;
    	for(int i=0;i<n;i++)
    		for(int j=0;j<=K;j++)
    			for(int k=0;k<=m[i] && k*a[i]<=j;k++){
    				dp[i+1][j] +=dp[i][j-k*a[i]];
    			}
    	
    /*
    	if(dp[n][K])cout<<"yes"<<endl;
    	else cout<<"no"<<endl;*/
    	cout<<dp[n][K]<<endl;
    	return 0;				
    }



  • 相关阅读:
    P4370[Code+#4]组合数问题2【数学,堆】
    牛客挑战赛53G同源数组(Easy Version)【NTT】
    P3577[POI2014]TURTourism【状压dp】
    P1232[NOI2013]树的计数【思维】
    AS3 CookBook学习整理(十一)
    AS3 CookBook学习整理(十五)
    AS3 CookBook学习整理(十四)
    AS3 CookBook学习整理(十二)
    AS3 CookBook学习整理(八)
    AS3 CookBook学习整理(十六)
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3237053.html
Copyright © 2020-2023  润新知