题目背景
总共n个人排成一行,第i个人手上有ai张牌,且∑ni=1ai=m,每个人每次可以把自己手中的一张纸牌传递给身边的人,求至少多少次操作才能让每个人手中持有的纸牌数相等(保证n∣m)
思路求解
将每个人视为一个节点,给出纸牌/收到纸牌视为连边,边权为进行传递的纸牌张数。当整除的关系存在时,由于从整个图上来说每个节点互相可达,那么均分纸牌的可行性是显然的。接下来考虑最优方案。
首先,对于两个节点来说,给出再给回是没有意义的。因为可以直接等效为某一方的给出,节省交换次数。所以两个节点中有且仅有一条单向边(边权可为0)。
接下来将问题分隔为子问题进行考虑。由于一个节点与另一个相连节点只能存在一条单向边,且第一个节点只与第二个节点相连,所以先从它开始考虑。
若a1=mn,则直接考虑接下来n−1个节点构成的子问题(后续的都不和第一个节点再发生交换了);
若a1>mn,则将a1−mn张牌给a2,在a′2=a2+a1−mn的情况下考虑接下来n−1个节点构成的子问题;
若a1<mn,则向a2“索要”mn−a1张牌,即使a2<mn−a1也没关系,因为可以放在后面的子问题中解决这个“赊账”,在实际中表现为交换顺序的不同。
如此往复下来,直到解决了第n−1个节点的问题,第n个节点手上也一定已经恰好有了mn张纸牌。
由于每一步的操作都是必须且不能减少的,最优性易得,接下来就是如何进行计算。
计算
设xi表示第i个节点向第i+1个节点之间边的边权,若为正说明边由i指向i+1(给出),为负说明边由i+1指向i(拿来)。我们需要计算得到∑n−1i=1|xi|。为了方便表示,令t=mn。我们有如下的方程组(共n条方程):⎧⎪
⎪
⎪
⎪
⎪
⎪⎨⎪
⎪
⎪
⎪
⎪
⎪⎩a1−x1=ta2+x1−x2=t ⋮an−1+xn−2−xn−1=tan+xn−1=t
为了使结果更直观,不妨增加一个xn=0(在环形均分纸牌的时候它将具有实际意义)。方程组变为⎧⎪
⎪
⎪
⎪
⎪
⎪⎨⎪
⎪
⎪
⎪
⎪
⎪⎩a1+xn−x1=ta2+x1−x2=t ⋮an−1+xn−2−xn−1=tan+xn−1−xn=t,将其表示为矩阵方程Ax=b的形式,则A=⎛⎜
⎜
⎜
⎜
⎜
⎜
⎜⎝−100⋯11−10⋯0⋱⋮1−101−1⎞⎟
⎟
⎟
⎟
⎟
⎟
⎟⎠,x=⎛⎜
⎜
⎜
⎜⎝x1x2⋮xn⎞⎟
⎟
⎟
⎟⎠,b=⎛⎜
⎜
⎜
⎜⎝t−a1t−a2⋮t−an⎞⎟
⎟
⎟
⎟⎠
依次对A和b做第i行加到i+1行(i=1,2⋯n−1)的行变换(以防读者没有学过线性代数,其实就是方程相加的化简啦!),可得到A′=⎛⎜
⎜
⎜
⎜
⎜
⎜
⎜⎝−100⋯1−10⋯1⋱⋮−110⎞⎟
⎟
⎟
⎟
⎟
⎟
⎟⎠,b′=⎛⎜
⎜
⎜
⎜⎝t−a12t−(a1+a2)⋮nt−(a1+a2+⋯+an)⎞⎟
⎟
⎟
⎟⎠
同时,nt=nmn=m=∑ni=1ai。现在第n行表示一个"0x=0"形式的方程,自然xn=0不影响这个方程组的可解性。令si=∑ni=1,将xn=0往回代,可得|xi|=|i∗t−si|。如此一来,均分纸牌的计算问题也就解决了。
环形均分纸牌
个人觉得这个问题难以讨论出断成链的可能性,所以不妨沿用原题的思路,将xn视为n到1连的边,同理正为给出,负为拿来。没有了xn=0的限制后,上面的方程组仍然成立,同时可知xn取任意值均有解。|xi|=|i∗t−si−xn|(i=1,2⋯n),若记bi=i∗t−si,则总代价表示为∑ni=1|bi−xn|。这样就可以转化为“货仓选址”的模型:将bi进行排序后,若n为奇数则取xn=b(n+1)/2,若n为偶数则取bn/2∼bn/2+1中的任一整数,即可得到最小代价。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效