我遇到了一个看起来很简单的问题,但是花了一天时间(在MatLab中)我就无法解决这个问题。
考虑一下集:
@ # ID
--------------
A 3 #1
A 3 #2
B 4 #3
B 4 #4
B 4 #5
C 2 #6
C 2 #7
C 2 #8
C 2 #9
D 1 #10
D 1 #11
E 2 #12
E 2 #13
... ... ...
我想找到所有可能的方法来合并第二列加起来的行数最多(并且尽可能接近)5。
约束:第一列必须是唯一的,但我需要显示每个ID。订单并不重要。为了给出更好的想法,这里有一些有用和无用输出的例子(显示比解释更快)。我将使用ID列来引用该行,因为实际输出将是3D矩阵。 (所以我们在这里挤压行维以简化)
通缉:
#1 #6
#1 #7
#1 #8
#1 #9
#1 #10
#1 #11
#1 #12
#1 #13
#2 #6
#2 #7
#2 #8
#2 #9
#2 #10
#2 #11
#2 #12
#2 #13
这将是所需输出的开始。 Everyything总计最多4或5,加起来最多4(#1#11或#2#10),没有更多有效的行可以添加第二列。
不需要的:
#6 #7 #10
即使这加起来为5,第一列在#5和#6中也不是唯一的。
#2 #10
#10 #2
第二列的总和尽可能接近5并且所有字母(第一列)在同一行内不同,但它们基本相同,只是顺序不同。应该省略相同组合的排列(不要关心弹出哪种可能的安排)
到目前为止我想出的算法只使用了#34;字母的第一个出现" (第1栏)或者一旦他们找到所有A-C组合(第一个字母可以加起来为5),他们就会去B并且没有注意到A-D-E或其他可能性。
EDIT2:
我想我已经明白了:
clearvars
SongList = cell(1,30,23);
m = 0;
for i=1:length(Info_Matrix)-3 % Infomatrix is the set with the @, # and ID. (and a lot more othe rirrelevant columns)
for k=1:length(Info_Matrix)-i
clearvars('SongsPlayed')
SongsPlayed(1,:) = Info_Matrix(i,:);
n = 1;
m = m+1;
TotalTime = cell2mat(Info_Matrix(i,15));
for j=i+k:length(Info_Matrix)
if TotalTime + cell2mat(Info_Matrix(j,15)) > 3600 %In the example we summed up to 5; here we sum up to 3600. If we try to add an element to our current collection that makes the total of the values in column 15 of the given set exceed 3600, do nothing.
elseif any(strcmp(SongsPlayed(:,1),Info_Matrix(j,1))) %If the name (@) is already in our current collection, do nothing.
else
TotalTime = TotalTime + cell2mat(Info_Matrix(j,15));
n = n+1;
SongsPlayed(n,:) = Info_Matrix(j,:);
SongList(m,1:length(SongsPlayed(:,1)),:) = SongsPlayed;
end
end
end
end
谢谢!
答案 0 :(得分:0)
从桶的角度思考。您有4个桶,值为1到4.在第一个桶中有一个桶,编号为10和11.在第二个桶中有两个桶,一个桶的值为6到9,另一个桶的值为12和13等等。
我们创建一个数组,其中外部桶的值重复次数与内部桶一样多次:[1,2,2,3,4]
计算所有理想的组合:[1,2,2],[1,4],[2,2],[2,3],[4]
现在你必须采取所有可能的组合来构建上面的组合。除了[2,3] => [C,A],[E,A]每种组合只有一种可能性。
之后,你必须为上面的每个组合组合所有桶的每个数量,例如对于[D,C,E](1,2,2)=> [10,11] x [6,7,8,9] x [12,13]给出2 * 4 * 2 = 16种组合。
所以有三个步骤,每个步骤都可能爆炸(比指数更差)。无论你对它进行多少优化,这似乎都不可行。