想不通这个算法的通用名叫什么?
Can't figure out what the generic name of this algorithm is called?
我刚刚做了一个 Top Coder SRM,其中有一个问题我无法解决。我正在尝试在线搜索算法的详细信息,但我似乎无法找到它。
问题围绕着以下几行:
你有一个数组,例如 [12, 10, 4]
每一轮,您可以应用 9,3,1 的任意排列从 [12,10,4]
中减去
Return 数组中所有数字达到 0 所需应用的最小排列数。
有什么帮助吗?
编辑:让我稍微描述一下,以便更好地理解问题。
One question would be
input: [12 10 4]
output: 2 (minimum rounds)
How it would work:
[12 10 4] - [9 3 1] = [3 7 3]
[12 10 4] - [9 1 3] = [3 9 1]
[12 10 4] - [3 9 1] = ..
[12 10 4] - [3 1 9] = ..
[12 10 4] - [1 3 9] =
[12 10 4] - [1 9 3] =
[3 7 3] - [3 9 1] = ...
..
[9 1 3] - [9 1 3] = [0 0 0] <-- achieved with only two permutation subtractions
编辑 2:
这里是 topcoder 问题:
http://community.topcoder.com/stat?c=problem_statement&pm=13782
编辑3:
任何人都可以解释重叠子问题和最优子结构,如果他们认为解决方案是动态规划的话?
编辑:
在看到原始问题后,这里是为上述问题 link 中提供的每个测试用例提供正确输出的解决方案,如果你想输入 {60},你应该给出{60,0,0} .
基本思路是,你需要让它们最后都小于或等于零,所以如果数字可以被 3 整除,你可以通过减去 9 或 3 得到零,如果不能整除,减去 1 到使其能被 3
整除
首先,对给定的三元组进行排序,然后
- 检查最大数是否能被3整除,如果是,减去9仍能被3整除
- 现在检查下一个最大的数,如果它能被 3 整除,则减去 3,否则减去 1
- 如果最大数不能被3整除,减去1使其可以被3整除
- 现在将下一个最大的数减去 9,将另一个数减去 3
这里是实现
#include <iostream>
#include <algorithm>
#include<cmath>
using namespace std;
int f(int* a,int k){
sort(a,a+3);
if(a[2]<=0 )
{cout << k<< endl ;
return 0;}
if(a[1]<=0){
cout << k+ceil((double)a[2]/9) << endl;
return 0;
}
if(a[2]%3==0 ){
a[2]=a[2]-9;
if(a[1]%3==0 )
{
a[1] = a[1] -3;
a[0] = a[0] -1;
}
else{
if(a[2]%2==0 && (a[1]-1)%2==0 && a[1]!=0){
a[2]=a[2] +9 -3;
a[1] = a[1] -9;
a[0] = a[0]-1;
}
else{
a[1] = a[1] -1;
a[0] = a[0] - 3;}
}
return f(a,++k);
}
else{
a[2] = a[2] -1;
a[1] = a[1] -9;
a[0]=a[0] -3;
return f(a,++k);
}
}
int main() {
int a[] = {54,18,6};
f(a,0);
return 0;
}
希望对您有所帮助
示例:
输入是 [12,4,10]
排序 [12,4,10] -> [12,10,4]
现在检查最大数是否能被 3
整除,这里 Yes
所以
[12-9,10,4] -> [3,10,4]
现在检查可被 3
整除的下一个最大数,此处 N0
所以
[3,10-1,4-3] ->[3,9,1]
现在增加计数并将其传递给函数 (recursive)
输入 -> [3,9,1]
排序[3,9,1] -> [9,3,1]
现在检查最大数是否能被 3
整除,这里 Yes
所以[9-9,3,1] -> [0,3,1]
现在检查可被 3
整除的下一个最大数,此处 Yes
所以[0,3-3,1-1] -> [0,0,0]
现在增加计数并传递数组
因为最大的元素是 0
,我们将打印计数,即 2
设元素个数为n
,设p1到pn!为数组的排列你想减去,让 A 成为你的原始数组。那么你想要线性系统的自然数解
A - k1*p1 - ... - kn! *pn! = 0
相当于
A = k1*p1 + ... + kn! *pn!
其中 0
是全为零的 n
-item 数组。由于 ℕ^n
不是 ℕ
-向量 space,因此您无法使用明显的线性代数解决方案来解决这个问题;实际上,在自然数上寻找线性系统的解一般是 NP-complete by a reduction from subset sum。我无法根据您的临时问题版本调整缩减,所以也许考虑一下。它应该保持 NP-hard,至少这是我所期望的。
可以用动态规划求解。如果您查看动态规划问题的常见解决方案,它们遵循相同的通用结构。我们使用一个数组来存储达到每个值所需的最少排列数,并使用嵌套循环依次更新每个值。答案将以 d[0][0][0]
结尾,这是达到 [0, 0, 0].
所需的排列数
public static int count(int a, int b, int c) {
int[][] permutations = {{9, 3, 1}, {9, 1, 3}, {1, 9, 3}, {1, 3, 9}, {3, 9, 1}, {3, 1, 9}};
int[][][] d = new int[a + 1][b + 1][c + 1];
// Set initial values to high value to represent no solution.
for(int x = 0; x <= a; x++) {
for(int y = 0; y <= b; y++) {
for(int z = 0; z <= c; z++) {
d[x][y][z] = Integer.MAX_VALUE / 2;
}
}
}
// Set number of permutations for initial value to 0.
d[a][b][c] = 0;
// Update all values.
for(int x = a; x >= 0; x--) {
for(int y = b; y >= 0; y--) {
for(int z = c; z >= 0; z--) {
for(int[] p:permutations) {
// Update count from [x, y, z] -> [nx, ny, nz] using permutation p.
int nx = x - p[0];
int ny = y - p[1];
int nz = z - p[2];
if(nx >= 0 && ny >= 0 && nz >= 0) {
d[nx][ny][nz] = Math.min(d[nx][ny][nz], d[x][y][z] + 1);
}
}
}
}
}
// Return final answer.
return d[0][0][0];
}
我刚刚做了一个 Top Coder SRM,其中有一个问题我无法解决。我正在尝试在线搜索算法的详细信息,但我似乎无法找到它。
问题围绕着以下几行: 你有一个数组,例如 [12, 10, 4]
每一轮,您可以应用 9,3,1 的任意排列从 [12,10,4]
中减去Return 数组中所有数字达到 0 所需应用的最小排列数。
有什么帮助吗?
编辑:让我稍微描述一下,以便更好地理解问题。
One question would be
input: [12 10 4]
output: 2 (minimum rounds)
How it would work:
[12 10 4] - [9 3 1] = [3 7 3]
[12 10 4] - [9 1 3] = [3 9 1]
[12 10 4] - [3 9 1] = ..
[12 10 4] - [3 1 9] = ..
[12 10 4] - [1 3 9] =
[12 10 4] - [1 9 3] =
[3 7 3] - [3 9 1] = ...
..
[9 1 3] - [9 1 3] = [0 0 0] <-- achieved with only two permutation subtractions
编辑 2:
这里是 topcoder 问题: http://community.topcoder.com/stat?c=problem_statement&pm=13782
编辑3: 任何人都可以解释重叠子问题和最优子结构,如果他们认为解决方案是动态规划的话?
编辑:
在看到原始问题后,这里是为上述问题 link 中提供的每个测试用例提供正确输出的解决方案,如果你想输入 {60},你应该给出{60,0,0} .
基本思路是,你需要让它们最后都小于或等于零,所以如果数字可以被 3 整除,你可以通过减去 9 或 3 得到零,如果不能整除,减去 1 到使其能被 3
整除首先,对给定的三元组进行排序,然后
- 检查最大数是否能被3整除,如果是,减去9仍能被3整除
- 现在检查下一个最大的数,如果它能被 3 整除,则减去 3,否则减去 1
- 如果最大数不能被3整除,减去1使其可以被3整除
- 现在将下一个最大的数减去 9,将另一个数减去 3
这里是实现
#include <iostream>
#include <algorithm>
#include<cmath>
using namespace std;
int f(int* a,int k){
sort(a,a+3);
if(a[2]<=0 )
{cout << k<< endl ;
return 0;}
if(a[1]<=0){
cout << k+ceil((double)a[2]/9) << endl;
return 0;
}
if(a[2]%3==0 ){
a[2]=a[2]-9;
if(a[1]%3==0 )
{
a[1] = a[1] -3;
a[0] = a[0] -1;
}
else{
if(a[2]%2==0 && (a[1]-1)%2==0 && a[1]!=0){
a[2]=a[2] +9 -3;
a[1] = a[1] -9;
a[0] = a[0]-1;
}
else{
a[1] = a[1] -1;
a[0] = a[0] - 3;}
}
return f(a,++k);
}
else{
a[2] = a[2] -1;
a[1] = a[1] -9;
a[0]=a[0] -3;
return f(a,++k);
}
}
int main() {
int a[] = {54,18,6};
f(a,0);
return 0;
}
希望对您有所帮助
示例:
输入是 [12,4,10]
排序 [12,4,10] -> [12,10,4]
现在检查最大数是否能被 3
整除,这里 Yes
所以
[12-9,10,4] -> [3,10,4]
现在检查可被 3
整除的下一个最大数,此处 N0
所以
[3,10-1,4-3] ->[3,9,1]
现在增加计数并将其传递给函数 (recursive)
输入 -> [3,9,1]
排序[3,9,1] -> [9,3,1]
现在检查最大数是否能被 3
整除,这里 Yes
所以[9-9,3,1] -> [0,3,1]
现在检查可被 3
整除的下一个最大数,此处 Yes
所以[0,3-3,1-1] -> [0,0,0]
现在增加计数并传递数组
因为最大的元素是 0
,我们将打印计数,即 2
设元素个数为n
,设p1到pn!为数组的排列你想减去,让 A 成为你的原始数组。那么你想要线性系统的自然数解
A - k1*p1 - ... - kn! *pn! = 0
相当于
A = k1*p1 + ... + kn! *pn!
其中 0
是全为零的 n
-item 数组。由于 ℕ^n
不是 ℕ
-向量 space,因此您无法使用明显的线性代数解决方案来解决这个问题;实际上,在自然数上寻找线性系统的解一般是 NP-complete by a reduction from subset sum。我无法根据您的临时问题版本调整缩减,所以也许考虑一下。它应该保持 NP-hard,至少这是我所期望的。
可以用动态规划求解。如果您查看动态规划问题的常见解决方案,它们遵循相同的通用结构。我们使用一个数组来存储达到每个值所需的最少排列数,并使用嵌套循环依次更新每个值。答案将以 d[0][0][0]
结尾,这是达到 [0, 0, 0].
public static int count(int a, int b, int c) {
int[][] permutations = {{9, 3, 1}, {9, 1, 3}, {1, 9, 3}, {1, 3, 9}, {3, 9, 1}, {3, 1, 9}};
int[][][] d = new int[a + 1][b + 1][c + 1];
// Set initial values to high value to represent no solution.
for(int x = 0; x <= a; x++) {
for(int y = 0; y <= b; y++) {
for(int z = 0; z <= c; z++) {
d[x][y][z] = Integer.MAX_VALUE / 2;
}
}
}
// Set number of permutations for initial value to 0.
d[a][b][c] = 0;
// Update all values.
for(int x = a; x >= 0; x--) {
for(int y = b; y >= 0; y--) {
for(int z = c; z >= 0; z--) {
for(int[] p:permutations) {
// Update count from [x, y, z] -> [nx, ny, nz] using permutation p.
int nx = x - p[0];
int ny = y - p[1];
int nz = z - p[2];
if(nx >= 0 && ny >= 0 && nz >= 0) {
d[nx][ny][nz] = Math.min(d[nx][ny][nz], d[x][y][z] + 1);
}
}
}
}
}
// Return final answer.
return d[0][0][0];
}