有一个矩阵,m×n。几组人在某些地方找到了。在以下示例中,有三个组,数字4表示此组中有四个人。现在我们想在矩阵中找到一个会合点,以便移动到该点的所有组的成本是最小的。至于如何计算将一个组移动到另一个点的成本,请参阅以下示例。
组1:(0,1),4
第2组:(1,3),3
第3组:(2,0),5
. 4 . .
. . . 3
5 . . .
如果所有这三个组都转移到(1,1),则成本为: 4 *((1-0)+(1-1))+ 5 *((2-1)+(1-0))+ 3 *((1-1)+(3-1))
我的想法是:
首先,这个二维问题可以简化为两个一维问题。 在一维问题中,我可以证明最佳位置必须是这些组中的一个。 通过这种方式,我可以给出一个O(G ^ 2)算法。(G是组的数量)。
使用迭代器的示例进行说明:
{( - 100,0,100),(100,0,100),(0,1,1)},(X,Y,人口)
对于x,{(-100,100),(100,100),(0,1)},0是最好的。
对于y,{(0,100),(0,100),(1,1)},0是最好的。
所以它是(0,0)
有没有更好的解决方案来解决这个问题。
答案 0 :(得分:1)
我喜欢注意到目标函数可以被分解以给出两个一维问题的总和的想法。剩下的问题看起来很像我的加权中位数(注意“在”http://www.stat.ucl.ac.be/ISdidactique/Rhelp/library/R.basic/html/weighted中解决了以下优化问题。 median.html“或考虑当你偏离加权中位数时目标函数会发生什么变化。”
上面的URL似乎表示加权中位数需要时间n log n,我猜这意味着您可以通过对数据进行排序然后进行线性传递来计算加权中位数来获得他们的声明。您必须排序的数字在[0,m]和[0,n]范围内,因此如果m和n很小,理论上可以做得更好,或者 - 当然 - 如果给出预先排序的数据。
想一想,我不明白为什么你不能用线性时间随机算法找到加权中位数,类似于用来找中位数的线性时间随机算法(http://en.wikibooks.org / wiki / Algorithms / Randomization #find-median) - 重复选择一个随机元素,用它来划分剩余的项目,并计算出加权中位数应该在哪一半。这给你预期的线性时间。
答案 1 :(得分:1)
我认为这可以在O(n> m?n:m)时间和O(n> m?n:m)空间中解决。 我们必须找到k点中所有y坐标的x坐标和中位数的中位数,答案为(x_median,y_median);
假设此函数接受以下输入:
int k= 4+3+5 = 12;
坐标数组:
struct coord_t c[12] = {(0,1),(0,1),(0,1), (0,1), (1,3), (1,3),(1,3),(2,0),(2,0),(2,0),(2,0),(2,0)};
c.int size = n>m ? n:m;
让坐标的输入为坐标数组。 coord_t c [k]
struct coord_t {
int x;
int y;
};
1. My idea is to create an array of size = n>m?n:m;
2. int array[size] = {0} ; //initialize all the elements in the array to zero
for(i=0;i<k;i++)
{
array[c[i].x] = +1;
count++;
}
int tempCount =0;
for(i=0;i<k;i++)
{
if(array[i]!=0)
{
tempCount += array[i];
}
if(tempCount >= count/2)
{
break;
}
}
int x_median = i;
//similarly with y coordinate.
int array[size] = {0} ; //initialize all the elements in the array to zero
for(i=0;i<k;i++)
{
array[c[i].y] = +1;
count++;
}
int tempCount =0;
for(i=0;i<k;i++)
{
if(array[i]!=0)
{
tempCount += array[i];
}
if(tempCount >= count/2)
{
break;
}
}
int y_median = i;
coord_t temp;
temp.x = x_median;
temp.y= y_median;
return temp;
带有k点的MxM矩阵的示例工作代码:
*问题 给定一个MxM网格。和N人在网格上随意放置。找到所有人的最佳会面点。 / / 回答: 找出人们所有x坐标的中位数。 找出人们所有位置的y坐标的中位数。 * /
#include<stdio.h>
#include<stdlib.h>
typedef struct coord_struct {
int x;
int y;
}coord_struct;
typedef struct distance {
int count;
}distance;
coord_struct toFindTheOptimalDistance (int N, int M, coord_struct input[])
{
coord_struct z ;
z.x=0;
z.y=0;
int i,j;
distance * array_dist;
array_dist = (distance*)(malloc(sizeof(distance)*M));
for(i=0;i<M;i++)
{
array_dist[i].count =0;
}
for(i=0;i<N;i++)
{
array_dist[input[i].x].count +=1;
printf("%d and %d\n",input[i].x,array_dist[input[i].x].count);
}
j=0;
for(i=0;i<=N/2;)
{
printf("%d\n",i);
if(array_dist[j].count !=0)
i+=array_dist[j].count;
j++;
}
printf("x coordinate = %d",j-1);
int x= j-1;
for(i=0;i<M;i++)
array_dist[i].count =0;
for(i=0;i<N;i++)
{
array_dist[input[i].y].count +=1;
}
j=0;
for(i=0;i<N/2;)
{
if(array_dist[j].count !=0)
i+=array_dist[j].count;
j++;
}
int y =j-1;
printf("y coordinate = %d",j-1);
z.x=x;
z.y =y;
return z;
}
int main()
{
coord_struct input[5];
input[0].x =1;
input[0].y =2;
input[1].x =1;
input[1].y =2;
input[2].x =4;
input[2].y =1;
input[3].x = 5;
input[3].y = 2;
input[4].x = 5;
input[4].y = 2;
int size = m>n?m:n;
coord_struct x = toFindTheOptimalDistance(5,size,input);
}
答案 2 :(得分:0)
你的算法很好,并将问题分成两个一维问题。时间复杂度为O(nlogn)。
你只需要将每一组人分成n个单独的人,所以每个人左右,上,下的每一步都是1。我们只需要找到(n + 1)/第2个人分别代表行和列的位置。
考虑你的样本。 {(-100,0,100),(100,0,100),(0,1,1)}。
让我们拿出行号。它是{(-100,100),(100,100),(0,1)},这意味着100人站在-100,100人站在100,1人站在0。
按x排序,它是{( - 100,100),(0,1),(100,100)}。总共有201人,所以我们只需要设置第101人所在的位置。它是0,这就是答案。
列号使用相同的算法。 {(0,100),(0,100),(1,1)},并且它已经排序。第101位是0,所以列的答案也是0。
答案是(0,0)。
答案 3 :(得分:0)
我可以想到一维问题的O(n)解,这反过来意味着你可以解决O(n + m + G)中的原始问题。
假设人们站在这样的位置,a_0,a_1,... a_n-1:a_0人在0点,a_1在1点。然后是伪码的解决方案
cur_result = sum(i*a_i, i = 1..n-1)
cur_r = sum(a_i, i = 1..n-1)
cur_l = a_0
for i = 1:n-1
cur_result = cur_result - cur_r + cur_l
cur_r = cur_r - a_i
cur_l = cur_l + a_i
end
你需要找到一点,其中cur_result是最小的
所以你需要O(n)+ O(m)来解决1d问题+ O(G)来构建它们,这意味着总复杂度为O(n + m + G)。
或者,您可以使用相同的想法在O(G * log G)(或O(G),如果数据已排序)中求解1d。从预期的组数中选择一个。
答案 4 :(得分:0)
你可以在O(G Log G)时间内解决这个问题,将它减少为你提到的两个一维问题。
至于如何在一个维度上解决它,只需对它们进行排序并逐个浏览它们并计算成本。对于每个点,该计算可以在O(1)时间内完成。 如果x和y坐标足够小,可以使用桶/基数排序,也可以避免使用Log(G)组件。
答案 5 :(得分:0)
受到kilotaras的想法的启发。对于这个问题,似乎有一个O(G)解决方案。 由于每个人都同意二维问题可以减少到两个一维问题。我不会再重复一次。我只关注如何解决一维问题 与O(G)。
假设人们像这样站着,[0],[1],...... [n-1]。有一个[i]人站在现场我。有G点有人(G <= n)。假设这些G点是g [1],g [2],...,g [G],其中gi在[0,...,n-1]中。在不失一般性的情况下,我们也可以假设g [1]&lt; g [2]&lt; ......&lt;克[G]。
不难证明最佳斑点必须来自这些G斑点。我会过去的 如果你们有兴趣,可以在这里证明并将其作为练习。
由于上述观察,我们可以计算移动到每个组的位置的成本,然后选择最小的一个。有一个明显的O(G ^ 2)算法来做到这一点。
但是使用kilotaras的想法,我们可以在O(G)中做到(没有排序)。
cost[1] = sum((g[i]-g[1])*a[g[i]], i = 2,...,G) // the cost of moving to the
spot of first group. This step is O(G).
cur_r = sum(a[g[i]], i = 2,...,G) //How many people is on the right side of the
second group including the second group. This step is O(G).
cur_l = a[g[1]] //How many people is on the left side of the second group not
including the second group.
for i = 2:G
gap = g[i] - g[i-1];
cost[i] = cost[i-1] - cur_r*gap + cur_l*gap;
if i != G
cur_r = cur_r - a[g[i]];
cur_l = cur_l + a[g[i]];
end
end
最低成本[i]就是答案。
使用示例5 1 0 3来说明算法。 在这个例子中,
n = 4,G = 3。
g [1] = 0,g [2] = 1,g [3] = 3.
a [0] = 5,a [1] = 1,a [2] = 0,a [3] = 3.
(1)cost [1] = 1 * 1 + 3 * 3 = 10,cur_r = 4,cur_l = 5.
(2)成本[2] = 10 - 4 * 1 + 5 * 1 = 11,间隙= g [2] - g [1] = 1,cur_r = 4 - a [g [2]] = 3 ,cur_l = 6。
(3)成本[3] = 11 - 3 * 2 + 6 * 2 = 17,缺口= g [3] - g [2] = 2.