【动态规划】【中位数】【C++算法】1478. 安排邮筒

简介: 【动态规划】【中位数】【C++算法】1478. 安排邮筒

# 作者推荐

【深度优先搜索】【树】【图论】2973. 树中每个节点放置的金币数目

本文涉及知识点

动态规划汇总

LeetCode1478. 安排邮筒

给你一个房屋数组houses 和一个整数 k ,其中 houses[i] 是第 i 栋房子在一条街上的位置,现需要在这条街上安排 k 个邮筒。

请你返回每栋房子与离它最近的邮筒之间的距离的 最小 总和。

答案保证在 32 位有符号整数范围以内。

示例 1:

输入:houses = [1,4,8,10,20], k = 3

输出:5

解释:将邮筒分别安放在位置 3, 9 和 20 处。

每个房子到最近邮筒的距离和为 |3-1| + |4-3| + |9-8| + |10-9| + |20-20| = 5 。

示例 2:

输入:houses = [2,3,5,12,18], k = 2

输出:9

解释:将邮筒分别安放在位置 3 和 14 处。

每个房子到最近邮筒距离和为 |2-3| + |3-3| + |5-3| + |12-14| + |18-14| = 9 。

示例 3:

输入:houses = [7,4,6,1], k = 1

输出:8

示例 4:

输入:houses = [3,6,14,10], k = 4

输出:0

提示:

n == houses.length

1 <= n <= 100

1 <= houses[i] <= 104

1 <= k <= n

数组 houses 中的整数互不相同。

动态规划

原理

houser[i,j]之间安装邮筒,安装到正中间的房子是最优解。

a,假定房子数是奇数,假定共有2n+1个房子。假定左边有i1个房子,右边有i2个房子。如果i1 < i2,则右移可以缩短距离;i1 > i2,则左移可以缩短距离。如果邮筒不在屋子上,则i1永远不会等于i2。i1==i2,则必定在最中间的屋子。i+(j-i)/2。

b,屋子为偶数,在中间的两坐房子之间,才会让i1和i2。其实中间两间房子的任何一间房子都可以。

可以统一为:i+(j-i)/2

确切的说{ 左边及本身的房子数小于右边的房子数,右移动。 右边及本身的房子数小于左边的房子数,左移动。 \begin{cases} 左边及本身的房子数小于右边的房子数,右移动。\\ 右边及本身的房子数小于左边的房子数,左移动。\\ \end{cases}{左边及本身的房子数小于右边的房子数,右移动。右边及本身的房子数小于左边的房子数,左移动。 → \rightarrow 稳定状态下,必须

{ i 1 > = i 2 , i 1 < = i 2 → i 1 = = i 2 邮筒不在房子上 i 1 + 1 > = i 2 , i 2 + 1 > = i 1 → a b s ( i 1 − i 2 ) < = 1 邮筒在房子上 → \begin{cases} i1 >=i2,i1 <=i2 \rightarrow i1==i2 & 邮筒不在房子上 \\ i1+1>=i2,i2+1 >= i1 \rightarrow abs(i1-i2)<=1 & 邮筒在房子上\\ \end{cases} \rightarrow{i1>=i2,i1<=i2i1==i2i1+1>=i2,i2+1>=i1abs(i1i2)<=1邮筒不在房子上邮筒在房子上

如果房子数量是奇数

{ 邮筒不在房子上 i 1 = = i 2 → ( i 1 + i 2 ) 是偶数 → 房子总数是奇数矛盾 邮筒在房子上且 i 1 等于 i 2 正中间的房子 邮筒在房子上且 i 1 和 i 2 相差 1 假定 11 + 1 = i 2 → i 1 + i 2 + 1 是偶数,和总数是奇数矛盾 → \begin{cases} 邮筒不在房子上& i1==i2 \rightarrow (i1+i2)是偶数 \rightarrow 房子总数是奇数矛盾 \\ 邮筒在房子上且i1等于i2 & 正中间的房子 \\ 邮筒在房子上且i1和i2相差1 & 假定11+1=i2 \rightarrow i1+i2+1是偶数,和总数是奇数矛盾 \\ \end{cases} \rightarrow邮筒不在房子上邮筒在房子上且i1等于i2邮筒在房子上且i1i2相差1i1==i2(i1+i2)是偶数房子总数是奇数矛盾正中间的房子假定11+1=i2i1+i2+1是偶数,和总数是奇数矛盾如果房子的数量是奇数则只能安装在最中间。

如果房子数量是偶数

{ 邮筒不在房子上 i 1 = = i 2 → 中间两间房子的空地 邮筒在房子上且 i 1 等于 i 2 i 1 + i 2 + 1 是奇数,与假设矛盾 邮筒在房子上且 i 1 和 i 2 相差 1 中间任意两间房子 → \begin{cases} 邮筒不在房子上& i1==i2 \rightarrow 中间两间房子的空地 \\ 邮筒在房子上且i1等于i2 & i1+i2+1是奇数,与假设矛盾 \\ 邮筒在房子上且i1和i2相差1 & 中间任意两间房子 \\ \end{cases} \rightarrow邮筒不在房子上邮筒在房子上且i1等于i2邮筒在房子上且i1i2相差1i1==i2中间两间房子的空地i1+i2+1是奇数,与假设矛盾中间任意两间房子

如果房间数是偶数,则中间的两间房子及之间的空地都是最优解。

预处理

vDis[i][j] ,记录一个邮筒到house[i,j]的距离之和。houses要先排序。

动态规划的状态表示

dp[i][j] 表示 j个邮筒支持前i栋房最小距离。

动态规划的状态方程

通过前者状态更新后置状态。

k = 1 i + k < = h o u s e s . l e n g t h \Large_{k=1}^{i+k <= houses.length}k=1i+k<=houses.length pre[i+k][j+1] = min( ⋯ \cdots,pre[i][j]+vDis[⋯ \cdots])

动态规划的初始值

dp[0][0]=0 ,其它INT_MAX,表示非法值。

动态规划的填表顺序

i从小到大,j从小到大。

动态规划的返回值

dp.back()[k]

代码

核心代码

class Solution {
public:
  int minDistance(vector<int>& houses, int K) {
    m_c = houses.size();
    sort(houses.begin(), houses.end());
    vector<vector<int>> vDis(m_c, vector<int>(m_c));
    for (int center = 0; center < m_c; center++)
    {
      {
        int iDis = 0;
        for (int i = center, j = center; (i >= 0) && (j < m_c); i--, j++)
        {
          iDis += houses[j] - houses[i];
          vDis[i][j] = iDis;
        }
      }
      {
        int iDis = 0;
        for (int i = center, j = center + 1; (i >= 0) && (j < m_c); i--, j++)
        {
          iDis += houses[j] - houses[i];
          vDis[i][j] = iDis;
        }
      }
    }
    vector<vector<int>> dp(m_c + 1, vector<int>(K + 1, INT_MAX));
    dp[0][0] = 0;
    for (int i = 0; i <= m_c; i++)
    {
      for (int j = 0; j < K; j++)
      {
        if (INT_MAX == dp[i][j])
        {
          continue;
        }
        for (int m = 1; m + i <= m_c; m++)
        {
          dp[m + i][j + 1] = min(dp[m + i][j + 1],dp[i][j]+vDis[i][i+m-1]);
        }
      }
    }
    return dp.back().back();
  }
  int m_c;
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{
  assert(t1 == t2);
}
template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
  if (v1.size() != v2.size())
  {
    assert(false);
    return;
  }
  for (int i = 0; i < v1.size(); i++)
  {
    Assert(v1[i], v2[i]);
  }
}
int main()
{ 
  vector<int> houses;
  int k;
  {
    Solution sln;
    houses = { 7,4,6,1 };
    k = 1;
    auto res = sln.minDistance(houses, k);
    Assert(8, res);
  }
  {
    Solution sln;
    houses = { 1, 4, 8, 10, 20 };
    k = 3;
    auto res = sln.minDistance(houses, k);
    Assert(5, res);
  }
  {
    Solution sln;
    houses = { 2,3,5,12,18 };
    k = 2;
    auto res = sln.minDistance(houses, k);
    Assert(9, res);
  }
  
  {
    Solution sln;
    houses = { 3,6,14,10 };
    k = 4;
    auto res = sln.minDistance(houses, k);
    Assert(0, res);
  }
}

2023年2月版

class Solution {

public:

int minDistance(vector& houses, int k) {

const int iNotMay = 1000 * 1000 * 10;

std::sort(houses.begin(), houses.end());

m_c = houses.size();

vector pre(m_c);

for (int i = 0; i < m_c; i++)

{

pre[i] = Cost(houses, 0, i + 1);

}

for (int iK = 2; iK <= k; iK++)

{

vector dp(m_c, iNotMay);

for (int iHouse = 0; iHouse < houses.size(); iHouse++)

{

for (int pr = 0; pr < iHouse; pr++)

{

if (iNotMay == pre[pr])

{

continue;

}

dp[iHouse] = min(dp[iHouse], pre[pr] + Cost(houses, pr+1, iHouse + 1));

}

}

pre.swap(dp);

}

return pre.back();

}

int Cost(const vector& houses,int left, int r)

{

int iCost = 0;

int iMean = houses[left + (r - left) / 2];

for (int i = left; i < r; i++)

{

iCost += abs(houses[i] - iMean);

}

return iCost;

}

int m_c;

};

2023年7月版

class Solution {

public:

int minDistance(vector& houses, int k) {

m_c = houses.size();

sort(houses.begin(), houses.end());

vector<vector> vCost(m_c, vector(m_c));

for(int i= 0 ;i < m_c; i++ )

for (int j = i+1; j < m_c; j++)

{

int iMidValue = houses[i] + (houses[j] - houses[i]) / 2;

int cost = 0;

int k = i+1;

for (; houses[k] <= iMidValue; k++)

{

cost += houses[k] - houses[i];

}

for (; k < j; k++)

{

cost += houses[j] - houses[k];

}

vCost[i][j] = cost;

}

const int iNotMay = 1000 * 1000 * 10;

vector<vector> dp(m_c + 1, vector(k + 1, iNotMay));

dp[0][0] = 0;

dp[0][1] = 0;

vector vBegin(m_c);

{

int iSum = 0;

for (int i = 1; i < m_c; i++)

{

iSum += (houses[i] - houses[i - 1]) * i;

vBegin[i] = iSum;

}

}

for (int i = 1; i < m_c; i++)

{

for (int prePos = 0; prePos < i; prePos++)

{

for (int preK = 0; preK < k; preK++)

{

if (iNotMay == dp[prePos][preK])

{

continue;

}

if (0 == preK)

{

dp[i][preK + 1] = vBegin[i];

continue;

}

dp[i][preK + 1] = min(dp[i][preK + 1],dp[prePos][preK] + vCost[prePos][i]);

}

}

}

vector vEnd(m_c);

{

int iSum = 0;

for (int i = m_c - 2; i >= 0; i–)

{

iSum += (houses[i + 1] - houses[i]) * (m_c - 1 - i);

vEnd[i] = iSum;

}

}

int iRet = iNotMay;

for (int i = k-1; i < m_c; i++)

{

iRet = min(iRet, dp[i][k] +vEnd[i]);

}

return iRet;

}

int m_c;

};


相关文章
|
5月前
|
机器学习/深度学习 存储 算法
动态规划算法深度解析:0-1背包问题
0-1背包问题是经典的组合优化问题,目标是在给定物品重量和价值及背包容量限制下,选取物品使得总价值最大化且每个物品仅能被选一次。该问题通常采用动态规划方法解决,通过构建二维状态表dp[i][j]记录前i个物品在容量j时的最大价值,利用状态转移方程避免重复计算子问题,从而高效求解最优解。
672 1
|
9月前
|
存储 监控 算法
基于 C++ 哈希表算法实现局域网监控电脑屏幕的数据加速机制研究
企业网络安全与办公管理需求日益复杂的学术语境下,局域网监控电脑屏幕作为保障信息安全、规范员工操作的重要手段,已然成为网络安全领域的关键研究对象。其作用类似网络空间中的 “电子眼”,实时捕获每台电脑屏幕上的操作动态。然而,面对海量监控数据,实现高效数据存储与快速检索,已成为提升监控系统性能的核心挑战。本文聚焦于 C++ 语言中的哈希表算法,深入探究其如何成为局域网监控电脑屏幕数据处理的 “加速引擎”,并通过详尽的代码示例,展现其强大功能与应用价值。
206 2
|
10月前
|
存储 算法 C++
Windows共享文件:探秘C++实现的B树索引算法奇境
在数字化时代,Windows共享文件的高效管理至关重要。B树算法以其自平衡多路搜索特性,在文件索引与存储优化中表现出色。本文探讨B树在Windows共享文件中的应用,通过C++实现具体代码,展示其构建文件索引、优化数据存储的能力,提升文件检索效率。B树通过减少磁盘I/O操作,确保查询高效,为企业和个人提供流畅的文件共享体验。
|
9月前
|
监控 算法 数据处理
基于 C++ 的 KD 树算法在监控局域网屏幕中的理论剖析与工程实践研究
本文探讨了KD树在局域网屏幕监控中的应用,通过C++实现其构建与查询功能,显著提升多维数据处理效率。KD树作为一种二叉空间划分结构,适用于屏幕图像特征匹配、异常画面检测及数据压缩传输优化等场景。相比传统方法,基于KD树的方案检索效率提升2-3个数量级,但高维数据退化和动态更新等问题仍需进一步研究。未来可通过融合其他数据结构、引入深度学习及开发增量式更新算法等方式优化性能。
235 17
|
8月前
|
存储 机器学习/深度学习 算法
基于 C++ 的局域网访问控制列表(ACL)实现及局域网限制上网软件算法研究
本文探讨局域网限制上网软件中访问控制列表(ACL)的应用,分析其通过规则匹配管理网络资源访问的核心机制。基于C++实现ACL算法原型,展示其灵活性与安全性。文中强调ACL在企业与教育场景下的重要作用,并提出性能优化及结合机器学习等未来研究方向。
226 4
|
7月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
205 0
|
8月前
|
机器学习/深度学习 存储 算法
基于 C++ 布隆过滤器算法的局域网上网行为控制:URL 访问过滤的高效实现研究
本文探讨了一种基于布隆过滤器的局域网上网行为控制方法,旨在解决传统黑白名单机制在处理海量URL数据时存储与查询效率低的问题。通过C++实现URL访问过滤功能,实验表明该方法可将内存占用降至传统方案的八分之一,查询速度提升约40%,假阳性率可控。研究为优化企业网络管理提供了新思路,并提出结合机器学习、改进哈希函数及分布式协同等未来优化方向。
254 0
|
10月前
|
存储 监控 算法
基于 C++ 哈希表算法的局域网如何监控电脑技术解析
当代数字化办公与生活环境中,局域网的广泛应用极大地提升了信息交互的效率与便捷性。然而,出于网络安全管理、资源合理分配以及合规性要求等多方面的考量,对局域网内计算机进行有效监控成为一项至关重要的任务。实现局域网内计算机监控,涉及多种数据结构与算法的运用。本文聚焦于 C++ 编程语言中的哈希表算法,深入探讨其在局域网计算机监控场景中的应用,并通过详尽的代码示例进行阐释。
210 4
|
11月前
|
存储 算法 安全
企业员工数据泄露防范策略:基于 C++ 语言的布隆过滤器算法剖析[如何防止员工泄密]
企业运营过程中,防范员工泄密是信息安全领域的核心议题。员工泄密可能致使企业核心数据、商业机密等关键资产的流失,进而给企业造成严重损失。为应对这一挑战,借助恰当的数据结构与算法成为强化信息防护的有效路径。本文专注于 C++ 语言中的布隆过滤器算法,深入探究其在防范员工泄密场景中的应用。
249 8
|
4月前
|
机器学习/深度学习 算法 机器人
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
459 0