找回密码
 注册
Simdroid-非首页
查看: 160|回复: 12

[讨论]找出集合中求和是原集合一半的子集合

[复制链接]
发表于 2013-12-25 09:44:21 | 显示全部楼层 |阅读模式 来自 河北廊坊
题目来自Cody,就是找出集合的子集,使得子集的和为原集合的一半
  1. Given a vector x, return the indices to elements that will sum to exactly half of the sum of all elements.

  2. Example:

  3. Input  x  = [1 2 3 4 5 6 7]
  4. Output xi = [1 6 7]
  5. because

  6. sum(x) = 28
  7. sum(x([1 6 7])) = 14
  8. The answer is not necessarily unique and the order is unimportant. We will just test to make sure that sum(x)/2 is sum(x(xi))
复制代码
以下是测试函数
  1. 1
  2. %%
  3. x = [1 2 3 4 5 6 7];
  4. xi = split_it(x);
  5. assert(isequal(sum(x(xi)),sum(x)/2));

  6. 2
  7. %%
  8. x = [2 2 2 2 2 2];
  9. xi = split_it(x);
  10. assert(isequal(sum(x(xi)),sum(x)/2));

  11. 3
  12. %%
  13. x = [2     5     4     5     4];
  14. xi = split_it(x);
  15. assert(isequal(sum(x(xi)),sum(x)/2));

  16. 4
  17. %%
  18. x = [1     3     1     1     9     7];
  19. xi = split_it(x);
  20. assert(isequal(sum(x(xi)),sum(x)/2));

  21. 5
  22. %%
  23. x = primes(100);
  24. xi = split_it(x);
  25. assert(isequal(sum(x(xi)),sum(x)/2));
复制代码
希望大家一起讨论

原题目链接:http://www.mathworks.cn/matlabcentral/cody/problems/660-find-a-subset-that-divides-the-vector-into-equal-halves
发表于 2013-12-25 14:32:17 | 显示全部楼层 来自 北京
Simdroid开发平台
还是有难度的,首先个人觉得全遍历组合可能会比较慢,给出随机数组合的solution:
  1. function ans= split_it(x)
  2. len=length(x)
  3. d=randi(len,[10000,fix(len/2)]);
  4. idx = arrayfun(@(i)sum(x(unique(d(i,:)))),1:length(d))'==sum(x)/2;
  5. find(idx,1,'first')
  6. unique(d(ans,:))
  7. end
复制代码

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2013-12-25 15:52:55 | 显示全部楼层 来自 北京
本帖最后由 rocwoods 于 2013-12-25 16:05 编辑

我也是用的随机的方法。

  1. function ans = split_it(x)
  2. ind = 1:length(x);
  3. while ~any(cumsum(x(ind))==sum(x)/2)
  4.     ind = randperm(length(x));      
  5. end
  6. ind(1:find(cumsum(x(ind))==sum(x)/2,1,'first'));
  7. end

复制代码

评分

1

查看全部评分

回复 不支持

使用道具 举报

 楼主| 发表于 2013-12-25 16:45:28 | 显示全部楼层 来自 河北廊坊
本帖最后由 qibbxxt 于 2013-12-25 16:50 编辑

求解方程的方法
  1. function ans = split_it(x)
  2. bintprog([],[],[],x,sum(x)/2);
复制代码

评分

3

查看全部评分

回复 不支持

使用道具 举报

发表于 2013-12-25 18:06:00 | 显示全部楼层 来自 北京
size改进到32了。
  1. function ans = split_it(x)
  2. while 1
  3.     randi(2,length(x),1);
  4.     if diff(accumarray(ans,x(:)))
  5.     else
  6.         ans==1;
  7.         break
  8.     end   
  9. end
复制代码

点评

随机数全相同时,diff结果为[],会进入else语句,此时计算结果不对  发表于 2013-12-25 22:35
感觉也是随机数列举比较容易理解。正好可以仔细研究下吴某的accumarray,赞!  发表于 2013-12-25 20:07

评分

2

查看全部评分

回复 不支持

使用道具 举报

 楼主| 发表于 2013-12-25 22:38:29 | 显示全部楼层 来自 河北廊坊

稍加修改
  1. function ans = split_it(x)
  2. while 1
  3.     randi(2,length(x),1);
  4.     if diff(accumarray(ans,x(:))) == 0
  5.         ans == 1;
  6.         break
  7.     end   
  8. end
复制代码

评分

1

查看全部评分

回复 不支持

使用道具 举报

 楼主| 发表于 2013-12-25 23:15:38 | 显示全部楼层 来自 河北廊坊
  1. function ans = split_it(x)
  2. x;
  3. while x * ans'
  4.    randsrc(1,length(x));
  5. end
  6. ans == 1;
复制代码

评分

1

查看全部评分

回复 不支持

使用道具 举报

头像被屏蔽
发表于 2013-12-27 10:33:27 | 显示全部楼层 来自 武汉大学
提示: 该帖被管理员或版主屏蔽
回复 不支持

使用道具 举报

发表于 2013-12-30 12:10:52 | 显示全部楼层 来自 英国
随机:
  1. function ans = split_it(x)
  2.    while 1
  3.             length(x);
  4.             randperm(ans, randi(ans));
  5.             if sum(x(ans))==sum(x)/2
  6.                   break
  7.             end
  8.    end
  9. end
复制代码
遍历:
  1. function ans = split_it(x)
  2.       for  k = 0:2^length(x)-1
  3.               find(dec2bin(k, length(x))-'0');
  4.               if(sum(x(ans))==sum(x)/2)
  5.                        break
  6.               end
  7.      end
  8. end
复制代码

点评

赞,dec2bin也可以用de2bi或者bitget来试一试,另外能否找到普遍的解法  发表于 2013-12-30 15:04

评分

1

查看全部评分

回复 不支持

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Simapps系列直播

Archiver|小黑屋|联系我们|仿真互动网 ( 京ICP备15048925号-7 )

GMT+8, 2024-10-1 21:40 , Processed in 0.065328 second(s), 23 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表