三个数中的最大成对递减数
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) -> (1,0,1)
你从第二个和第三个索引中删除了1。
从给定的 3 个数字中选择任意 2 个,并在可能的情况下执行给定的操作。抱歉我编辑了问题@Yonlif
您能否编辑您的问题以将您正在使用的代码直接放入问题文本中?这样可以更轻松地评估您在做什么。
完成@templatetypedef
你不需要min
:在else
下,你知道a[0]+a[1]<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
从最小到最大进行排序。然后评估数字适合哪种模式。要寻找的模式包括:
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 > 0) ? 1 : 0
与a > 0
相同
@phuclv - 好点。当我尝试在整数和布尔值之间进行转换时,我总是期待一些编译器警告,我只是猜测任何隐式转换都会发出警告,而无需尝试记住规则。以上是关于三个数中的最大成对递减数的主要内容,如果未能解决你的问题,请参考以下文章
求做一个C++程序 求四个数中的最大数和最小数差值.要求用函数实现该功能.
javascript基础程序(算出一个数的平方值算出一个数的阶乘输出!- !- !- !- !- -! -! -! -! -! 函数三个数中的最大数)