我得到2个数组,输入和输出数组。目标是通过将给定步骤中的1值移位到其相邻元素,将输入数组转换为输出数组。例如:输入数组为[0,0,8,0,0],输出数组为[2,0,4,0,2]。这里第一步是[0,1,7,0,0],第二步是[0,1,6,1,0],依此类推。
有效地执行此操作的算法是什么?我正在考虑执行BFS但是我们必须从每个元素执行BFS,这可能是指数级的。有谁能建议解决这个问题?
答案 0 :(得分:3)
我认为你可以简单地通过扫描每个方向来跟踪当前数组和所需输出数组中的累积值(在那个方向上),并根据需要在你前面推送值:
scan from the left looking for first cell where
cumulative value > cumulative value in desired output
while that holds move 1 from that cell to the next cell to the right
scan from the right looking for first cell where
cumulative value > cumulative value in desired output
while that holds move 1 from that cell to the next cell to the left
对于您的示例,步骤将是:
FWD: [0,0,8,0,0] [0,0,7,1,0] [0,0,6,2,0] [0,0,6,1,1] [0,0,6,0,2]
REV: [0,1,5,0,2] [0,2,4,0,2] [1,1,4,0,2] [2,0,4,0,2]
答案 1 :(得分:2)
一个简单的贪婪算法可以工作,并以最少的步骤完成工作。该函数返回任务所需的总步骤数。
int shift(std::vector<int>& a,std::vector<int>& b){
int n = a.size();
int sum1=0,sum2=0;
for (int i = 0; i < n; ++i){
sum1+=a[i];
sum2+=b[i];
}
if (sum1!=sum2)
{
return -1;
}
int operations=0;
int j=0;
for (int i = 0; i < n;)
{
if (a[i]<b[i])
{
while(j<n and a[j]==0){
j++;
}
if(a[j]<b[i]-a[i]){
operations+=(j-i)*a[j];
a[i]+=a[j];
a[j]=0;
}else{
operations+=(j-i)*(b[i]-a[i]);
a[j]-=(b[i]-a[i]);
a[i]=b[i];
}
}else if (a[i]>b[i])
{
a[i+1]+=(a[i]-b[i]);
operations+=(a[i]-b[i]);
a[i]=b[i];
}else{
i++;
}
}
return operations;
}
这里-1
是一个特殊值,意味着给定的数组无法转换为所需的数组。
时间复杂度:O(n)。
答案 2 :(得分:1)
我认为BFS实际上可以工作。
请注意n*O(n+m)
= O(n^2+nm)
,因此不是指数型。
你也可以使用:Floyd-Warshall算法和约翰逊算法,对于“平面”图形权重为1,或者甚至以新的方式将顶点按实际距离连接,并可能节省一些迭代。
希望它有所帮助:)
答案 3 :(得分:1)
void transform(int[] in, int[] out, int size)
{
int[] state = in.clone();
report(state);
while (true)
{
int minPressure = 0;
int indexOfMinPressure = 0;
int maxPressure = 0;
int indexOfMaxPressure = 0;
int pressureSum = 0;
for (int index = 0; index < size - 1; ++index)
{
int lhsDiff = state[index] - out[index];
int rhsDiff = state[index + 1] - out[index + 1];
int pressure = lhsDiff - rhsDiff;
if (pressure < minPressure)
{
minPressure = pressure;
indexOfMinPressure = index;
}
if (pressure > maxPressure)
{
maxPressure = pressure;
indexOfMaxPressure = index;
}
pressureSum += pressure;
}
if (minPressure == 0 && maxPressure == 0)
{
break;
}
boolean shiftLeft;
if (Math.abs(minPressure) > Math.abs(maxPressure))
{
shiftLeft = true;
}
else if (Math.abs(minPressure) < Math.abs(maxPressure))
{
shiftLeft = false;
}
else
{
shiftLeft = (pressureSum < 0);
}
if (shiftLeft)
{
++state[indexOfMinPressure];
--state[indexOfMinPressure + 1];
}
else
{
--state[indexOfMaxPressure];
++state[indexOfMaxPressure + 1];
}
report(state);
}
}