三个数中的最大成对递减数

Posted

技术标签:

【中文标题】三个数中的最大成对递减数【英文标题】:Maximum number of pairwise decrements in three numbers 【发布时间】:2020-03-28 20:04:08 【问题描述】:

给出 3 个非负整数 a,b,c

在单个操作中,只有当两个整数不为负时,我们才需要从它们中减去 1。

在给定的操作不可能之前,我们必须找到最大的可能操作数。

约束:1

示例: (1,2,3) -> (1,1,2) -> (1,0,1) -> (0,0,0) ,答案是 3 (1,1,8) -> (1,0,7) -> (0,0,6) ,答案是 2

任何方法或证据都会非常有帮助。

据我所知,我实际上已经编写了一个有效的代码,但我不知道它是否完全正确。

#include <bits/stdc++.h>
using namespace std;

#define fastio ios_base::sync_with_stdio(0); cin.tie(0)
#define LL long long 

int main()
   fastio;
   int t; cin>>t;
   while(t--)
      LL a[3]; cin>>a[0]>>a[1]>>a[2];
      sort(a,a+3);
      if(a[0]+a[1]>=a[2])
         LL ans = a[2] + (a[0]+a[1]-a[2])/2;
         cout<<ans;
      
      else 
         LL ans = a[1] + min(a[0],a[2]-a[1]);
         cout<<ans;
      
      cout<<"\n";
   

更新:事实证明我的解决方案是正确的,这里是完全相同的problem,和editorial

【问题讨论】:

我没看懂第一个例子,为什么(1,1,2) -&gt; (1,0,1)你从第二个和第三个索引中删除了1。 从给定的 3 个数字中选择任意 2 个,并在可能的情况下执行给定的操作。抱歉我编辑了问题@Yonlif 您能否编辑您的问题以将您正在使用的代码直接放入问题文本中?这样可以更轻松地评估您在做什么。 完成@templatetypedef 你不需要min:在else下,你知道a[0]+a[1]&lt;a[2],所以a[1] + min(a[0],a[2]-a[1])min(a[1]+a[0], a[1]+a[2]-a[1])a[0]+a[1]。这是有道理的:a[2] 足够大,你能做的最好的就是配对 a[0],a[2] 直到 a[0]==0 和配对 a[1],a[2] 直到 a[1]==0 【参考方案1】:

不就是这样吗:

对数字进行排序

1 2 3

total 0

减去第一个(并添加到总数中),使第二个尽可能接近,同时小于或等于第三个

0 2 2

total 1

减去第二个并添加到总数

0 0 0

total 3

?

2 2 2
0

0 1 1
2

0 0 0
3

function f(arr)
  arr.sort((a, b) => a - b);
  
  let [a, b, c] = arr;
  const max_from_c = c - b;
  
  if (max_from_c >= a)
    return a + b;

  let total = max_from_c;
  
  a = a - max_from_c;
  c = c - max_from_c;
  const smaller_half = Math.floor(a / 2);
  const larger_half = a < 2 ? a : Math.ceil(a / 2);
  c = c - larger_half;
  total = total + larger_half;
  b = b - smaller_half;
  total = total + smaller_half;

  return total + Math.min(b, c);


var arrays = [
  [1,2,3], // 3
  [1,1,8], // 2
  [3,4,5], // 6
  [1,1,1], // 1
  [1,1,2], // 2
  [2,1,2], // 2
  [2,2,2], // 3
  [3,3,2], // 4
  [10000,10000,10000] // 15000
];

for (let arr of arrays)
  console.log(JSON.stringify(arr));
  console.log(f(arr));
  console.log('');

【讨论】:

【参考方案2】:

我花了 3 次尝试才做到这一点。把这个问题误认为是动态规划问题是螺旋式下降

诀窍是认识到它可以在一个循环中解决,您可以在循环中不断地对a,b,c 从最小到最大进行排序。然后评估数字适合哪种模式。要寻找的模式包括:

集合中有 1 个或更少的正值:a=0, b=0, c=5 集合中有2个正值和一个零:a=0, b=3, c=10 3 个正值,全不同:a=5, b=11, c=88 3 个正值,都一样:a=10, b=10, c=10 3个正值,最小的两个相等:a=5, b=5, c=22 3个正值,最大的两个相等:a=3, b=5, c=5

在您确定a,b,c 属于上述列表中的哪个模式后,可以进行具体的快速缩减。其中许多将允许您跳出循环,而无需进一步减少集合。而且我认为以下代码可以运行,因此它最多只能遍历循环 2(或 3)次。 因此,这是一个 O(1) 解决方案

#include <iostream>
#include <algorithm>

using namespace std;

long long maxDeductions(long long a, long long b, long long c)

    long long total = 0;  // this is the running count of "deduction" steps made so far

    while (true)
    
        long long deduction = 0;  // scratch variable for math

        // sort a,b,c into ascending order
        long long sorttable[3] =  a,b,c ;
        sort(sorttable, sorttable + 3);
        a = sorttable[0];  // smallest
        b = sorttable[1];  // middle
        c = sorttable[2];  // largest

        // count the number of positive values among a,b,c    
        int positives = 0;
        positives += (a > 0);
        positives += (b > 0);
        positives += (c > 0);

        if (positives <= 1)
        
            // Nothing left to do, we can break out of the loop
            break;
        
        else if (positives == 2)
        
            // When there are only two positives left
            // The number of deductions that can be express computed.
            // as the smaller of the remaining positive values, that is: b
            //
            // ASSERT: (b <= c) && (b > 0) && (c > 0)
            deduction = b;
            total += deduction;
            break;
        
        else // three positives
        
            if ((a != b) && (b != c))    // 3 positives, all different
            
                // reduce the two larger values, b and c,  by the delta between b and a
                // this "b-a" amount is the number of deductions computed to  get the set a,b,c to have 
                // at least 2 identical numbers for the next set
                deduction = b - a;
                b = a;
                c -= deduction;
                total += deduction;
            
            else if ((a == b) && (b == c)) // 3 positives, all the same
            
                // when you have 3 identical values: N,N,N
                // It takes three steps to get to N-2,N-2,N-2
                // With a subtle tweak for odd vs even values of N, simple math can be used to 
                // deduce the remaining number of deductions

                if (a % 2) // odd
                
                    deduction = ((a - 1) / 2) * 3 + 1;
                
                else  // even
                
                    deduction = (a / 2) * 3;
                
                total += deduction;
                break;
            
            else if (c == b)   // 3 positives, largest two are the same, equivalent to all different
            
                deduction = b - a;
                b = a;
                c -= deduction;
                total += deduction;
            
            else if (a == b)   // 3 positives, smallest two are the same
            
                // this is the tricker one, but you can quickly see the pattern:
                // NNZ reduces in N*2 steps.  Example for N=5
                // 559 -> 548 -> 448 ->  437 -> 337 -> 326 -> 226 -> 215 -> 115 -> 104 -> 003
                // You can see every two reductions steps gets N,N,Z reduced to N-1,N-1,Z-1
                // Hence, exactly N*2 steps remaining
                total += (a * 2);
                break;
            
        

    
    return total;
;

【讨论】:

等等,我的想法有反例吗? (a &gt; 0) ? 1 : 0a &gt; 0 相同 @phuclv - 好点。当我尝试在整数和布尔值之间进行转换时,我总是期待一些编译器警告,我只是猜测任何隐式转换都会发出警告,而无需尝试记住规则。

以上是关于三个数中的最大成对递减数的主要内容,如果未能解决你的问题,请参考以下文章

求做一个C++程序 求四个数中的最大数和最小数差值.要求用函数实现该功能.

C 语言实例 - 判断三个数中的最大数。

javascript基础程序(算出一个数的平方值算出一个数的阶乘输出!- !- !- !- !- -! -! -! -! -! 函数三个数中的最大数)

用c#比较三个数的大小,并输出最大数。

值为1到99的100个数中有两个数相等,设计算法找出这两个数

c语言实践 给三个数输出最大的那个数