贪心并不难,难的是证明。
贪心并不难,难的是证明。
贪心并不难,难的是证明。
———— heidoudou
基本思路:先将数组
s
o
r
t
sort
sort一遍,然后用双指针i = 1
,j = n
,
i
f
(
a
i
+
a
j
>
w
)
if(a_i+a_j>w)
if(ai+aj>w),则将
a
j
a_j
aj单独分为一组,--j
,
e
l
s
e
else
else则将
a
i
a_i
ai和
a
j
a_j
aj分为一组,++i
,--j
证明:
- i f ( a i + a j > w ) if(a_i+a_j>w) if(ai+aj>w), a j a_j aj也不可能和其他任何一个 a k ( i < k < j ) a_k(i<k<j) ak(i<k<j)为一组 → \to → a j a_j aj单独一组
-
i
f
(
a
i
+
a
j
≤
w
)
if(a_i+a_j≤w)
if(ai+aj≤w){
i f if if a i a_i ai, a j a_j aj各为一组,那么就会比 a i a_i ai, a j a_j aj为一组的情况多出一组;
e l s e else else i f if if a i a_i ai单独一组, a j a_j aj与另一个 a k a_k ak为一组,那么 a j a_j aj, a k & a i a_k\And a_i ak&ai的组数 = a j = a_j =aj, a i & a k a_i\And a_k ai&ak的组数;
e l s e else else i f if if a j a_j aj单独一组, a i a_i ai与另一个 a k a_k ak为一组,那么 a i a_i ai, a k & a j a_k\And a_j ak&aj的组数 = a i = a_i =ai, a j & a k a_j\And a_k aj&ak的组数;
e l s e else else i f if if a i a_i ai与 a k a_k ak, a j a_j aj与 a m a_m am为一组,交换 a k & a j a_k \And a_j ak&aj后, ⟹ a i + a j ≤ w \implies a_i+a_j≤w ⟹ai+aj≤w, a k + a m ≤ a k + a j ≤ w ⟹ a_k+a_m≤a_k+a_j≤w \implies ak+am≤ak+aj≤w⟹
a i a_i ai, a k & a j a_k\And a_j ak&aj, a m a_m am的组数 = a i = a_i =ai, a j & a k a_j\And a_k aj&ak, a m a_m am的组数;
}
∴ ∴ ∴ 我们证明看子问题的最优解可以通过上述贪心过程得到
下面我们证明贪心后 ∑ ∑ ∑子问题的最优解就是全局最优解
设 a [ i . . . j ] a[i...j] a[i...j]问题为 P P P, P P P的贪心解为 S S S,经过贪心之后, ∑ ∑ ∑子问题 P ′ P' P′的最优解为 S ′ S' S′。如果 ∑ ∑ ∑子问题 P ′ P' P′的最优解 S ′ S' S′不是 P P P的最优解,那么我们先假设存在一个最优解 Z Z Z,可以通过上述证明过程后,使之变成相同 ∑ ∑ ∑子问题 P ′ P' P′的解 Z ′ Z' Z′,又 ∵ S > Z ∵S>Z ∵S>Z,而且二者贪心后的分组数是相同的, ∴ ∴ ∴ S ′ > Z ′ S'>Z' S′>Z′,这就与 S ′ S' S′为最优解相矛盾, → ∑ \to∑ →∑子问题的最优解 = = = 全局最优解
证毕 . 证毕. 证毕.
光知道贪心,贪心为什么可以得到最优解,你证明过么?
光知道贪心,贪心为什么可以得到最优解,你证明过么?
光知道贪心,贪心为什么可以得到最优解,你证明过么?
———— heidoudou
#include<bits/stdc++.h>
#define ll long long
#define maxn 30005
using namespace std;
inline int read(){
int x = 0; bool f = false; char ch = getchar();
while(!isdigit(ch)){if(ch == '-') f = true; ch = getchar();}
while(isdigit(ch)){x = x * 10 + ch - '0'; ch = getchar();}
return f ? -x : x;
}
inline void write(ll x){
if (x < 0) x = ~x + 1, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int w, n, p[maxn], ans;
int main(){
w = read(); n = read();
for(register int i = 1; i <= n; ++i) p[i] = read();
sort(p + 1, p + n + 1);
int i = 1, j = n;
while(i <= j){
if(p[i] + p[j] > w){++ans; --j;}
else{++ans; ++i; --j;}
}
write(ans); puts("");
return 0;
}