子集和问题(动态规划解法)
2018-02-20 12:30
162 查看
/*给出一个集合,以及一个测试数,求给集合的子集的和是否等于该数(如:给出 7 10 11 20 9,以及16,则输出ture,给出15则输出false)*/第一种:(递归版)
#include<stdio.h>
#include<string.h>
int solve_dp(int*p,int n,int key);
int solve_dp(int*p,int n,int key)
{
if(key==0)
return 1;//当key==0时,说明有这样一个子集(当然,若输入的key为0,则没有意义)
else if(n==0)
return p[0]==key;//当找到第0个时,key还不为0,判断p[0]==key?,是则存在,否则不存在
else if(p
>key)
return solve_dp(p,n-1,key);//如果第n个数大于key则放弃这个数,跳到下一个数
else
return solve_dp(p,n-1,key-p
)||solve_dp(p,n-1,key);//否则若第n个数比key小,则有两条路,//选或不选,选择这个数就让key减去它,否则跳过这个数,只要有一条路成立,则说明存在这样一个子集。}
int main()
{
int n,i,key;
printf("Input the length\n");
scanf("%d",&n);
int *p = malloc(n*sizeof(int));
printf("Input the array\n");
for(i=0; i<n; i++)
scanf("%d",&p[i]); for(i=0; i<100; i++)//进行多次测试
{
printf("Input the test number\n");
scanf("%d",&key);
if(solve_dp(p,n-1,key))//数组从0到n-1
printf("True\n");
else
printf("False\n");
}
return 0;
第二种(动态规划版/查表法)用一个二维数组来保存结果,避免重复过程。如下图,填完后输出右下角值(opt[n-1][key])(key值为5,p数组:10,5,2,7,9)
出口:1.当n==0时,判断p[0]==key? 2.当key==0时,真 3.当p[i]>key时,不选p[i] 4.否则,选择p[i]||不选p[i]
#include<stdio.h>
#include<string.h>
int solve_dp(int *p,int n,int key);
int solve_dp(int *p,int n,int key)
{
int i,j;
int**opt=malloc(n*sizeof(int));//定义二级指针(行数)
for(i=0; i<n; i++) //(每行都有多少列)
opt[i]=malloc((key+1)*sizeof(int *)); //注意二维数组的动态开辟方法 for(i = 0; i <= key; i++)
opt[0][i] = 0;//第一行(对应递归版n为0时的情况) for(i = 0; i < n; i++)
opt[i][0] = 1;//当key为0时,该列都为1
opt[0][p[0]]=1;//但如果p[0]==key,则该值为1(覆盖掉原来的0,上面注释为红色部分)
for(i=1; i<n; i++)//遍历p数组,以及二维数组的列
for(j=1; j<=key; j++)//二维数组的行
{
if(p[i]>j)
opt[i][j]=opt[i-1][j];
else
opt[i][j]=opt[i-1][j-p[i]]||opt[i-1][j];
}
for(i=0;i<n;i++)
{
for(j=0;j<=key;j++)
printf("%d ",opt[i][j]);
putchar('\n');
}//打印二维数组(用于验证) j=opt[n-1][key];//保存结果
free(opt);//及时释放掉二维数组
return j;
}int main()
{ int n,i,key;
printf("Input the length\n");
scanf("%d",&n);
int *p=malloc(n*sizeof(int));
printf("Input the array\n");
for(i=0; i<n; i++)
scanf("%d",&p[i]);
for(i=0; i<20; i++)
{
printf("Input the test number\n");
scanf("%d",&key);
if(solve_dp(p,n,key))
printf("True\n");
else
printf("False\n");
}
return 0;
}
#include<stdio.h>
#include<string.h>
int solve_dp(int*p,int n,int key);
int solve_dp(int*p,int n,int key)
{
if(key==0)
return 1;//当key==0时,说明有这样一个子集(当然,若输入的key为0,则没有意义)
else if(n==0)
return p[0]==key;//当找到第0个时,key还不为0,判断p[0]==key?,是则存在,否则不存在
else if(p
>key)
return solve_dp(p,n-1,key);//如果第n个数大于key则放弃这个数,跳到下一个数
else
return solve_dp(p,n-1,key-p
)||solve_dp(p,n-1,key);//否则若第n个数比key小,则有两条路,//选或不选,选择这个数就让key减去它,否则跳过这个数,只要有一条路成立,则说明存在这样一个子集。}
int main()
{
int n,i,key;
printf("Input the length\n");
scanf("%d",&n);
int *p = malloc(n*sizeof(int));
printf("Input the array\n");
for(i=0; i<n; i++)
scanf("%d",&p[i]); for(i=0; i<100; i++)//进行多次测试
{
printf("Input the test number\n");
scanf("%d",&key);
if(solve_dp(p,n-1,key))//数组从0到n-1
printf("True\n");
else
printf("False\n");
}
return 0;
第二种(动态规划版/查表法)用一个二维数组来保存结果,避免重复过程。如下图,填完后输出右下角值(opt[n-1][key])(key值为5,p数组:10,5,2,7,9)
出口:1.当n==0时,判断p[0]==key? 2.当key==0时,真 3.当p[i]>key时,不选p[i] 4.否则,选择p[i]||不选p[i]
P数组 \ key值 | 0 | 1 | 2 | 3 | 4 | 5 | |
| P[0]: 10 | 1 | 0 | 0 | 0 | 0 | 0 |
P[1]: 5 | 1 | 0. | 0 | 0 | 0 | 1 | |
P[2]: 2 | 1 | 0 | 1 | 0 | 0 | 1 | |
P[3]: 7 | 1 | 0 | 1 | 0 | 0 | 1 | |
P[4]: 9 | 1 | 0 | 1 | 0 | 0 | 1 |
#include<string.h>
int solve_dp(int *p,int n,int key);
int solve_dp(int *p,int n,int key)
{
int i,j;
int**opt=malloc(n*sizeof(int));//定义二级指针(行数)
for(i=0; i<n; i++) //(每行都有多少列)
opt[i]=malloc((key+1)*sizeof(int *)); //注意二维数组的动态开辟方法 for(i = 0; i <= key; i++)
opt[0][i] = 0;//第一行(对应递归版n为0时的情况) for(i = 0; i < n; i++)
opt[i][0] = 1;//当key为0时,该列都为1
opt[0][p[0]]=1;//但如果p[0]==key,则该值为1(覆盖掉原来的0,上面注释为红色部分)
for(i=1; i<n; i++)//遍历p数组,以及二维数组的列
for(j=1; j<=key; j++)//二维数组的行
{
if(p[i]>j)
opt[i][j]=opt[i-1][j];
else
opt[i][j]=opt[i-1][j-p[i]]||opt[i-1][j];
}
for(i=0;i<n;i++)
{
for(j=0;j<=key;j++)
printf("%d ",opt[i][j]);
putchar('\n');
}//打印二维数组(用于验证) j=opt[n-1][key];//保存结果
free(opt);//及时释放掉二维数组
return j;
}int main()
{ int n,i,key;
printf("Input the length\n");
scanf("%d",&n);
int *p=malloc(n*sizeof(int));
printf("Input the array\n");
for(i=0; i<n; i++)
scanf("%d",&p[i]);
for(i=0; i<20; i++)
{
printf("Input the test number\n");
scanf("%d",&key);
if(solve_dp(p,n,key))
printf("True\n");
else
printf("False\n");
}
return 0;
}
相关文章推荐
- 0-1背包问题及其动态规划求解之二——王晓东的书本解法
- 钢铁切割问题 动态规划(输出切割方案和带成本的解法)
- 0-1背包问题的两种解法(回溯法和动态规划)
- 整数拆分问题 动态规划解法
- 石子合并问题 --动态规划--解法1
- [动态规划]背包问题(找零/子集和/编辑距离)
- 程序员面试金典(动态规划):8(n)皇后问题(java解法)
- 0-1背包问题--动态规划解法
- 程序员面试金典(动态规划):返回某集合的所有子集(java解法)
- 数塔问题---动态规划解法
- 01背包问题--动态规划解法
- 活动选择问题——动态规划解法(自底向上)
- 程序员面试金典(动态规划):约瑟夫环问题(java解法)
- 01背包问题(当有的背包重量是非整数时)的递归(优化成动态规划+再用滚动数组优化)解法+一些动态规划(递归,搜索)的高级技巧
- 整数划分问题解法2-动态规划
- 约瑟夫问题(动态规划解法)
- 【转】 01背包问题 动态规划解法
- 01背包问题--动态规划解法(2)(转载)
- java--0-1背包问题--动态规划解法
- 同一问题的递归与动态规划解法