zoukankan      html  css  js  c++  java
  • 部分和问题---多重部分和问题---动态规划

    第一: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;				
    }



  • 相关阅读:
    深圳移动 神州行(大众卡/轻松卡/幸福卡)套餐资费(含香港日套餐)信息及使用方法
    PHP设置时区,记录日志文件的方法
    微信公众平台消息接口使用指南
    C#日期时间格式化
    使用CMD实现批量重命名[转]
    Python高效编程技巧
    实用WordPress后台MySQL操作命令
    ubuntu-wine
    Javascript 笔记与总结(2-8)对象2
    Swift5.3 语言指南(十) 枚举
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3237053.html
Copyright © 2011-2022 走看看