子集和问题
来源:互联网 发布:python help 函数 编辑:程序博客网 时间:2024/06/01 14:02
子集和问题:
集合s是一个有n个正整数构成的集合{w1,w2,……,wn},指定正整数c,判断正整数c,判断是否存在S的一个子集S1,使得w∈S1,∑w=c;
若子集和问题有解,则输出子集S1的元素;
1.说明:
设n个元素(正整数)存储在w数组中,应用动态规划设计求解;
目标函数: max(n)∑(i=1)xi wi
约束条件: (n)∑(i=1)xi wi<=c(xi∈{0,1},c,wi∈N*,i=1,2,……,n)
按构建S1选择每一个元素为一个阶段,共分为n个阶段;
(1)、建立递推关系;
设m(i,j)为集合S1距离c还差j,可取整数编号范围为:i,i+1,……,n的最大和,则:
当0<=j< w(i)时,整数w(i)不可选,m(i,j)与m(i+1,j)相同;
当j>=w(i)时,有两种选择:不选择整数w(i),这时最大值为m(i+1,j);选择整数w(i),这时已增加整数w(i),剩余差额为j-w(i),可以选择整数编号范围为i+1,……,n,最大值为m(i+1,j-w(i))+w(i);
我们期望的最大值是两者中的最大值,于是有递推关系:
| m(i+1,j) 0<=j<w(i) m(i,j)= | max(m(i+1,j),m(i+1,j-w(i))+w(i)) j>=w(i)
以上j与w(i)均为正整数,i=1,2,……,n,所求最优值为m(1,c);
(2)、递推计算最优值;
for(j=0;j<=c;j++) m[n][j]=0;for(j=w[n];j<=c;j++) /*首先计算m(n,j)*/ m[n][j]=w[n];for(i=n-1;i>=1;i--) /*递推计算m(i,j)*/ for(j=0;j<=c;j++) if(j>=w[i] && m[i+1][j]<m[i+1][j-w[i]]+w[i]) m[i][j]=m[i+1][j-w[i]]+w[i]; else m[i][j]=m[i+1][j];printf("%d",m[1][c]);
(3)、构造最优解;
构造最优解即选择构建集合S1的所有元素;
if(m[i][cw]>m[i+1][cw]) /*其中cw为当前与c差额,i=1,2,n-1*/ 选择w[i];else 不选择w[i];if(所选整数和!=m(1,c)) 选择w[n];
2.程序设计:
#define N 100#include<stdio.h>#include<stdlib.h>#include<time.h>int main(){ int n,c,i,j,s,t,cb,sb,w[N],m[N][10*N]; t=time(0)%1000; srand(t); /*随机数发生器初始化*/ printf("请确定S中正整数的个数n: "); scanf("%d",&n); printf("已知集合S的%d个正整数为: \n",n); for(s=0,i=1;i<=n;i++) /*随机产生n个正整数*/ { w[i]=rand()%(5*n)+10; s+=w[i]; printf("%3d",w[i]); } printf("\n请指定和c: "); scanf("%d",&c); if(c>s) { printf("集合所有整数之和不足,无解!\n"); return; } if(c==s) { printf("集合所有元素之和为%d!\n",c); return; } for(j=0;j<=w[n];j++) m[n][j]=0; /*确定初始条件*/ for(j=w[n];j<=c;j++) m[n][j]=w[n]; for(i=n-1;i>=1;i--) /*递推计算m(i,j)*/ for(j=0;j<=c;j++) if(j>=w[i] && m[i+1][j]<m[i+1][j-w[i]]+w[i]) m[i][j]=m[i+1][j-w[i]]+w[i]; else m[i][j]=m[i+1][j]; /*得最优值m(1,c)*/ if(m[1][c]!=c) { printf("无解!\n"); return; } else printf("所选元素为:"); cb=m[1][c]; for(sb=0,i=1;i<=n-1;i++) /*构造并输出所选元素*/ if(m[i][cb]>m[i+1][cb]) { cb-=w[i]; sb+=w[i]; printf("%3d",w[i]); } if(m[1][c]-sb==w[n]) { printf("%d",w[n]); sb+=w[n]; } printf(" (%d)\n",sb);}
3.程序运行示例及其注意事项:
请确定S中正整数的个数n: 15已知集合S的15个正整数为: 44 19 19 41 10 35 38 43 43 22 40 69 11 76 29请指定和c: 300子集和问题有解!所选元素为: 43 43 40 69 76 29 (300)
注意:程序设置了二维数组,限制了集合S中的元素不能太多,也不能太大,从而限制了该程序的应用范围;
1 0
- 子集和问题
- 子集和问题
- 子集和问题
- 8603 子集和问题
- 子集和问题
- 子集和问题
- 子集和问题
- 子集和问题
- 子集和问题
- 子集和问题
- 子集和问题
- 子集和问题
- 8603 子集和问题
- 子集和问题
- 子集和问题
- 子集和问题
- 子集和问题
- 子集和问题
- Binary Tree Level Order Traversal II
- 课程设计:小学生考试系统
- RAM ROM and Flash
- Protobuf使用手册
- js文章网站集锦
- 子集和问题
- 菜单对号标记
- 【File】——查找文件夹下所有文件的名称
- redis 安装
- 服务器总是被攻击
- AVRO : 常用知识总结
- Android design包自定义tablayout的底部导航栏
- js获得本周,本月,本季度,本年的开始日期和结束日期
- [学习笔记] bootstrap(八): 标签和徽章(比如消息通知的小数字)