我们都知道最大子段和可以这样写:
int sum = 0, ans = 0;
for(int i = 1; i <= n; i++) {
ans = max(ans, sum = max(0, sum + a[i]));
}
那么,最大子段和为什么是正确的呢?
小编也非常好奇,那么我们就来证明一下吧!
我们先用 Bird Meertens Formalism 写下一个证明:
M S S = ↑ / ⋅ + / ∗ ⋅ s e g s = ↑ / ⋅ + / ∗ ⋅ + + / ⋅ t a i l s ∗ ⋅ i n i t s = ↑ / ⋅ ( ↑ / ⋅ + / ∗ ⋅ t a i l s ) ∗ ⋅ i n i t s < ⊕ / ⋅ + + / = ⊕ / ⋅ ( ⊕ / ) ∗ > = ↑ ⋅ ⊙ ↛ 0 ∗ i n i t s < a ⊙ b = ( a + b ) ↑ 0 > = ↑ ⋅ ⊙ → 0 MSS\\=\uparrow/\cdot +/*\cdot segs\\=\uparrow/\cdot +/*\cdot ++/\cdot tails*\cdot inits\\=\uparrow/\cdot(\uparrow/\cdot +/*\cdot tails)*\cdot inits \ \ \ <\oplus/\cdot++/=\oplus/\cdot(\oplus/)*>\\=\uparrow \cdot \odot\nrightarrow_0*inits\ \ \ <a \odot b=(a+b)\uparrow 0>\\=\uparrow \cdot \odot\rightarrow_0 MSS=↑/⋅+/∗⋅segs=↑/⋅+/∗⋅++/⋅tails∗⋅inits=↑/⋅(↑/⋅+/∗⋅tails)∗⋅inits <⊕/⋅++/=⊕/⋅(⊕/)∗>=↑⋅⊙↛0∗inits <a⊙b=(a+b)↑0>=↑⋅⊙→0
但这里就有严谨的小朋友要问了, 这个证明真的是对的吗?
那么,让我们用 agda 证明吧!
(这份 15KB 的代码刷新了小编的代码长度记录)
module mss where
import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; _≢_; refl; trans; sym; cong; cong-app; subst)
open Eq.≡-Reasoning using (begin_; _≡⟨⟩_; step-≡; _∎)
open import Function using (id; _∘_)
open import Data.Integer
open import Data.Integer.Properties
data ℤ∞ : Set where
fin : ℤ → ℤ∞
-∞ : ℤ∞
_+'_ : ℤ∞ → ℤ∞ → ℤ∞
fin a +' fin b = fin (a + b)
fin a +' -∞ = -∞
-∞ +' -∞ = -∞
-∞ +' fin a = -∞
_⊔'_ : ℤ∞ → ℤ∞ → ℤ∞
fin a ⊔' fin b = fin (a ⊔ b)
fin a ⊔' -∞ = fin a
-∞ ⊔' -∞ = -∞
-∞ ⊔' fin a = fin a
module semigroup where
record IsSemigroup {A : Set} (_⊕_ : A → A → A) : Set where
field assoc : ∀ x y z → (x ⊕ y) ⊕ z ≡ x ⊕ (y ⊕ z)
open IsSemigroup public
ℤ-add-is-semigroup : IsSemigroup _+_
ℤ-add-is-semigroup .assoc = +-assoc
ℤ-⊔-is-semigroup : IsSemigroup _⊔_
ℤ-⊔-is-semigroup .assoc = ⊔-assoc
open import Data.List using (List; _++_; [])
open import Data.List.Properties using (++-assoc)
List-++-is-semigroup : ∀ {A : Set} → IsSemigroup {List A} _++_
List-++-is-semigroup .assoc = ++-assoc
open semigroup
ℤ∞-add-is-semigroup : IsSemigroup _+'_
ℤ∞-add-is-semigroup .assoc (fin x) (fin y) (fin z) rewrite ℤ-add-is-semigroup .assoc x y z = refl
ℤ∞-add-is-semigroup .assoc (fin x) (fin y) -∞ = refl
ℤ∞-add-is-semigroup .assoc (fin x) -∞ (fin z) = refl
ℤ∞-add-is-semigroup .assoc (fin x) -∞ -∞ = refl
ℤ∞-add-is-semigroup .assoc -∞ (fin x) (fin z) = refl
ℤ∞-add-is-semigroup .assoc -∞ (fin y) -∞ = refl
ℤ∞-add-is-semigroup .assoc -∞ -∞ (fin z) = refl
ℤ∞-add-is-semigroup .assoc -∞ -∞ -∞ = refl
ℤ∞-⊔-is-semigroup : IsSemigroup _⊔'_
ℤ∞-⊔-is-semigroup .assoc (fin x) (fin y) (fin z) rewrite ℤ-⊔-is-semigroup .assoc x y z = refl
ℤ∞-⊔-is-semigroup .assoc (fin x) (fin y) -∞ = refl
ℤ∞-⊔-is-semigroup .assoc (fin x) -∞ (fin z) = refl
ℤ∞-⊔-is-semigroup .assoc (fin x) -∞ -∞ = refl
ℤ∞-⊔-is-semigroup .assoc -∞ (fin y) (fin z) = refl
ℤ∞-⊔-is-semigroup .assoc -∞ -∞ (fin z) = refl
ℤ∞-⊔-is-semigroup .assoc -∞ (fin y) -∞ = refl
ℤ∞-⊔-is-semigroup .assoc -∞ -∞ -∞ = refl
module monoid where
record IsMonoid {A : Set} (e : A) (_⊕_ : A → A → A) : Set where
field
is-semigroup : IsSemigroup _⊕_
identityˡ : ∀ x → e ⊕ x ≡ x
identityʳ : ∀ x → x ⊕ e ≡ x
open IsMonoid public
ℤ-add-is-monoid : IsMonoid +0 _+_
ℤ-add-is-monoid .is-semigroup = ℤ-add-is-semigroup
ℤ-add-is-monoid .identityˡ = +-identityˡ
ℤ-add-is-monoid .identityʳ = +-identityʳ
open import Data.List using (List; _++_; [])
open import Data.List.Properties using (++-identityˡ; ++-identityʳ)
List-++-is-monoid : ∀ {A : Set} → IsMonoid {List A} [] _++_
List-++-is-monoid .is-semigroup = List-++-is-semigroup
List-++-is-monoid .identityˡ = ++-identityˡ
List-++-is-monoid .identityʳ = ++-identityʳ
open monoid
ℤ∞-add-is-monoid : IsMonoid (fin +0) _+'_
ℤ∞-add-is-monoid .is-semigroup = ℤ∞-add-is-semigroup
ℤ∞-add-is-monoid .identityˡ (fin x) rewrite ℤ-add-is-monoid .identityˡ x = refl
ℤ∞-add-is-monoid .identityˡ -∞ = refl
ℤ∞-add-is-monoid .identityʳ (fin x) rewrite ℤ-add-is-monoid .identityʳ x = refl
ℤ∞-add-is-monoid .identityʳ -∞ = refl
ℤ∞-⊔-is-monoid : IsMonoid -∞ _⊔'_
ℤ∞-⊔-is-monoid .is-semigroup = ℤ∞-⊔-is-semigroup
ℤ∞-⊔-is-monoid .identityˡ (fin x) = refl
ℤ∞-⊔-is-monoid .identityˡ -∞ = refl
ℤ∞-⊔-is-monoid .identityʳ (fin x) = refl
ℤ∞-⊔-is-monoid .identityʳ -∞ = refl
ℤ-⊔+-distrib : ∀ (z x y : ℤ) → ((x ⊔ y) + z) ≡ ((x + z) ⊔ (y + z))
ℤ-⊔+-distrib z x y = mono-≤-distrib-⊔ (+-monoˡ-≤ z) x y
distrib : ∀ (z x y : ℤ∞) → ((x ⊔' y) +' z) ≡ ((x +' z) ⊔' (y +' z))
distrib (fin z) (fin x) (fin y) rewrite ℤ-⊔+-distrib z x y = refl
distrib (fin z) (fin x) -∞ = refl
distrib (fin z) -∞ (fin x) = refl
distrib (fin z) -∞ -∞ = refl
distrib -∞ (fin x) (fin y) = refl
distrib -∞ (fin x) -∞ = refl
distrib -∞ -∞ (fin x) = refl
distrib -∞ -∞ -∞ = refl
module MSS (
extensionality : ∀ {A : Set} {B : A → Set}
{f g : (x : A) → B x}
→ ((x : A) → f x ≡ g x)
---------------------
→ f ≡ g
) where
open import Data.Nat using (ℕ; _+_; zero; suc; _⊔_)
open import Data.List using (List; []; _∷_; [_]; _++_; foldl; foldr; map; scanl; scanr)
reduce : ∀ {A : Set} → (A → A → A) → A → List A → A
reduce _⊕_ e [] = e
reduce _⊕_ e (x ∷ xs) = _⊕_ x (reduce _⊕_ e xs)
map-rule : ∀ {A : Set} {B : Set} (f : A → B) (xs : List A) (ys : List A)
→ map f (xs ++ ys) ≡ (map f xs) ++ (map f ys)
map-rule f [] ys = refl
map-rule f (x ∷ xs) ys =
begin f x ∷ map f (xs ++ ys)
≡⟨ cong (_∷_ (f x)) (map-rule f xs ys) ⟩
f x ∷ map f xs ++ map f ys
∎
map-o-rule : ∀ {A : Set} {B : Set} {C : Set} (f : A → B) (g : B → C) (xs : List A)
→ (map g ∘ map f) xs ≡ map (g ∘ f) xs
map-o-rule f g [] = refl
map-o-rule f g (x ∷ xs) rewrite map-o-rule f g xs = refl
map-f-rule' : ∀ {A : Set} {B : Set} {f : A → B} {g : A → B} → f ≡ g → (xs : List A) → map f xs ≡ map g xs
map-f-rule' {f} {g} lam [] = refl
map-f-rule' {f} {g} lam (x ∷ xs) rewrite map-f-rule' lam xs | cong-app lam x = refl
map-f-rule : ∀ {A : Set} {B : Set} {f : A → B} {g : A → B} → f ≡ g → map f ≡ map g
map-f-rule {f} {g} lam = extensionality (map-f-rule' lam)
inits : ∀ {A : Set} → List A → List (List A)
inits = scanl _++_ [] ∘ map [_]
tails : ∀ {A : Set} → List A → List (List A)
tails [] = [] ∷ []
tails (x ∷ xs) = (x ∷ xs) ∷ tails xs
concat : ∀ {A : Set} → List (List A) → List A
concat = foldr _++_ []
segs : ∀ {A : Set} → List A → List (List A)
segs = concat ∘ map tails ∘ inits
sum : List ℤ∞ → ℤ∞
sum = reduce _+'_ (fin +0)
maximum : List ℤ∞ → ℤ∞
maximum = reduce _⊔'_ (-∞)
mss : List ℤ∞ → ℤ∞
mss = maximum ∘ map sum ∘ segs
mss-fast : List ℤ∞ → ℤ∞
mss-fast xs = maximum (scanl (λ a b → (a +' b) ⊔' (fin +0)) (fin +0) xs)
-- Did you know there are plenty of useful theorems in the standard library?
open import Data.Nat.Properties using (+-distribˡ-⊔; +-distribʳ-⊔)
-- +-distribˡ-⊔ : ∀ x y z → x + (y ⊔ z) ≡ (x + y) ⊔ (x + z)
-- +-distribʳ-⊔ : ∀ z x y → (x ⊔ y) + z ≡ (x + z) ⊔ (y + z)
reduce-lam : ∀ {A : Set} (_⊕_ : A → A → A) (e : A) (xs : List A) (ys : List A)
→ IsMonoid e _⊕_ → reduce _⊕_ e (xs ++ ys) ≡ (reduce _⊕_ e xs) ⊕ (reduce _⊕_ e ys)
reduce-lam _⊕_ e [] ys lam =
begin reduce _⊕_ e ([] ++ ys)
≡⟨ refl ⟩
reduce _⊕_ e ys
≡⟨ sym (identityˡ lam (reduce _⊕_ e ys)) ⟩
e ⊕ (reduce _⊕_ e ys)
≡⟨ refl ⟩
(reduce _⊕_ e []) ⊕ (reduce _⊕_ e ys) ∎
reduce-lam _⊕_ e (x ∷ xs) ys lam =
begin x ⊕ (reduce _⊕_ e (xs ++ ys))
≡⟨ cong (_⊕_ x) (reduce-lam _⊕_ e xs ys lam) ⟩
x ⊕ ((reduce _⊕_ e xs) ⊕ (reduce _⊕_ e ys))
≡⟨ sym (assoc (is-semigroup lam) x (reduce _⊕_ e xs) (reduce _⊕_ e ys)) ⟩
((x ⊕ (reduce _⊕_ e xs)) ⊕ reduce _⊕_ e ys)
∎
join-f-rule : ∀ {A : Set} {B : Set} (_⊕_ : B → B → B) (e : B) (f : A → B) (xs : List (List A)) →
IsMonoid e (_⊕_) → ((reduce _⊕_ e) ∘ map f ∘ concat) xs ≡ (reduce _⊕_ e) (map ((reduce _⊕_ e) ∘ (map f)) xs)
join-f-rule _⊕_ e f [] lam = refl
join-f-rule _⊕_ e f (x ∷ xs) lam =
begin (reduce _⊕_ e ∘ map f ∘ concat) (x ∷ xs)
≡⟨ refl ⟩
(reduce _⊕_ e) (map f (x ++ concat xs))
≡⟨ cong (reduce _⊕_ e) (map-rule f x (concat xs)) ⟩
(reduce _⊕_ e) (map f x ++ (map f (concat xs)))
≡⟨ reduce-lam _⊕_ e (map f x) (map f (concat xs)) lam ⟩
(reduce _⊕_ e (map f x)) ⊕ (reduce _⊕_ e (map f (concat xs)))
≡⟨ cong (_⊕_ (reduce _⊕_ e (map f x))) (join-f-rule _⊕_ e f xs lam) ⟩
((reduce _⊕_ e ∘ map f) x ⊕ reduce _⊕_ e (map (reduce _⊕_ e ∘ map f) xs))
∎
-- going from the back is convinient
folder-rule : ∀ {A : Set} (_⊕_ : A → A → A) (ep : A) (_⊗_ : A → A → A)
(et : A) (xs : List A) (p : A) (q : A) → IsMonoid ep _⊕_ → IsMonoid et _⊗_
→ (∀ (z x y : A) → (x ⊕ y) ⊗ z ≡ (x ⊗ z) ⊕ (y ⊗ z))
→ (reduce _⊗_ et (p ∷ xs)) ⊕ foldl (λ a b → (a ⊗ b) ⊕ et) q xs ≡ foldl (λ a b → (a ⊗ b) ⊕ et) (p ⊕ q) xs
folder-rule _⊕_ ep _⊗_ et [] p q l1 l2 l3 rewrite identityʳ l2 p = refl
folder-rule _⊕_ ep _⊗_ et (x ∷ xs) p q l1 l2 l3 =
begin (reduce _⊗_ et (p ∷ x ∷ xs) ⊕ foldl (λ a b → (a ⊗ b) ⊕ et) q (x ∷ xs))
≡⟨ refl ⟩
(reduce _⊗_ et (p ∷ x ∷ xs) ⊕ foldl (λ a b → (a ⊗ b) ⊕ et) ((q ⊗ x) ⊕ et) xs)
≡⟨ refl ⟩
(p ⊗ (x ⊗ reduce _⊗_ et xs)) ⊕ foldl (λ a b → (a ⊗ b) ⊕ et) ((q ⊗ x) ⊕ et) xs
≡⟨ sym (cong (_⊕ (foldl (λ a b → (a ⊗ b) ⊕ et) ((q ⊗ x) ⊕ et) xs)) (assoc (is-semigroup l2) p x (reduce _⊗_ et xs))) ⟩
((p ⊗ x) ⊗ reduce _⊗_ et xs) ⊕ foldl (λ a b → (a ⊗ b) ⊕ et) ((q ⊗ x) ⊕ et) xs
≡⟨ refl ⟩
reduce _⊗_ et ((p ⊗ x) ∷ xs) ⊕ foldl (λ a b → (a ⊗ b) ⊕ et) ((q ⊗ x) ⊕ et) xs
≡⟨ folder-rule _⊕_ ep _⊗_ et xs (p ⊗ x) ((q ⊗ x) ⊕ et) l1 l2 l3 ⟩
foldl (λ a b → (a ⊗ b) ⊕ et) ((p ⊗ x) ⊕ ((q ⊗ x) ⊕ et)) xs
≡⟨ sym (cong-app (cong (foldl (λ a b → (a ⊗ b) ⊕ et)) (assoc (is-semigroup l1) (p ⊗ x) (q ⊗ x) et)) xs) ⟩
foldl (λ a b → (a ⊗ b) ⊕ et) (((p ⊗ x) ⊕ (q ⊗ x)) ⊕ et) xs
≡⟨ sym (cong-app (cong (foldl (λ a b → (a ⊗ b) ⊕ et)) (cong (_⊕ et) (l3 x p q))) xs) ⟩
foldl (λ a b → (a ⊗ b) ⊕ et) (((p ⊕ q) ⊗ x) ⊕ et) xs
≡⟨ refl ⟩
foldl (λ a b → (a ⊗ b) ⊕ et) (p ⊕ q) (x ∷ xs)
∎
hornor-rule : ∀ {A : Set} (_⊕_ : A → A → A) (ep : A) (_⊗_ : A → A → A) (et : A)
→ IsMonoid ep _⊕_ → IsMonoid et _⊗_ → (∀ (z x y : A) → (x ⊕ y) ⊗ z ≡ (x ⊗ z) ⊕ (y ⊗ z)) -- distri
→ (xs : List A) → ((reduce _⊕_ ep) ∘ map (reduce _⊗_ et) ∘ tails) xs ≡ foldl (λ a b → (a ⊗ b) ⊕ et) et xs
hornor-rule _⊕_ ep _⊗_ et l1 l2 l3 [] =
(reduce _⊕_ ep ∘ map (reduce _⊗_ et)) (tails [])
≡⟨ refl ⟩
(reduce _⊕_ ep ∘ map (reduce _⊗_ et)) ([] ∷ [])
≡⟨ identityʳ l1 et ⟩
et
∎
hornor-rule _⊕_ ep _⊗_ et l1 l2 l3 (x ∷ xs) =
begin (reduce _⊕_ ep ∘ map (reduce _⊗_ et) ∘ tails) (x ∷ xs)
≡⟨ refl ⟩
(reduce _⊕_ ep ∘ map (reduce _⊗_ et)) ((x ∷ xs) ∷ tails xs)
≡⟨ refl ⟩
(reduce _⊕_ ep) ((reduce _⊗_ et (x ∷ xs)) ∷ map (reduce _⊗_ et) (tails xs))
≡⟨ refl ⟩
(reduce _⊗_ et (x ∷ xs)) ⊕ ((reduce _⊕_ ep) (map (reduce _⊗_ et) (tails xs)))
≡⟨ cong (_⊕_ (reduce _⊗_ et (x ∷ xs))) ( hornor-rule _⊕_ ep _⊗_ et l1 l2 l3 xs) ⟩
(reduce _⊗_ et (x ∷ xs)) ⊕ (foldl (λ a b → (a ⊗ b) ⊕ et) et xs)
≡⟨ folder-rule _⊕_ ep _⊗_ et xs x et l1 l2 l3 ⟩
foldl (λ a b → (a ⊗ b) ⊕ et) (x ⊕ et) xs
≡⟨ sym(cong-app (cong (foldl (λ a b → (a ⊗ b) ⊕ et)) (cong (_⊕ et) (identityˡ l2 x))) xs) ⟩
foldl (λ a b → (a ⊗ b) ⊕ et) et (x ∷ xs)
∎
hornor-rule-f : ∀ {A : Set} (_⊕_ : A → A → A) (ep : A) (_⊗_ : A → A → A) (et : A)
→ IsMonoid ep _⊕_ → IsMonoid et _⊗_ → (∀ (z x y : A) → (x ⊕ y) ⊗ z ≡ (x ⊗ z) ⊕ (y ⊗ z)) -- distri
→ ((reduce _⊕_ ep) ∘ map (reduce _⊗_ et) ∘ tails) ≡ foldl (λ a b → (a ⊗ b) ⊕ et) et
hornor-rule-f _⊕_ ep _⊗_ et l1 l2 l3 = extensionality (hornor-rule _⊕_ ep _⊗_ et l1 l2 l3)
fold-scan-rule : ∀ {A : Set} (f : A → A → A) (e : A) (p : A) (ps : List A) (xs : List A)
→ map (foldl f e) (scanl _++_ (p ∷ ps) (map [_] xs)) ≡ map (foldl f (f e p)) (scanl _++_ ps (map [_] xs))
fold-scan-rule f e p ps [] = refl
fold-scan-rule f e p ps (x ∷ xs) rewrite fold-scan-rule f e p (ps ++ (x ∷ [])) xs = refl
scan-rule : ∀ {A : Set} (f : A → A → A) (e : A) (xs : List A)
→ (map (foldl f e)) (inits xs) ≡ scanl f e xs
scan-rule f e [] = refl
scan-rule f e (x ∷ xs) =
begin e ∷ map (foldl f e) (scanl _++_ [ x ] (map [_] xs))
≡⟨ cong (_∷_ e) (fold-scan-rule f e x [] xs) ⟩
e ∷ map (foldl f (f e x)) (scanl _++_ [] (map [_] xs))
≡⟨ cong (_∷_ e) (scan-rule f (f e x) xs) ⟩
e ∷ scanl f (f e x) xs
∎
prof : ∀ (xs : List ℤ∞) → mss xs ≡ mss-fast xs
prof xs =
begin mss xs
≡⟨ refl ⟩
(maximum ∘ map sum ∘ concat ∘ map tails ∘ inits) xs
-- (max / ∘ + / * ∘ ++ / ) = max / ∘ (max / ∘ + / *) *
≡⟨ join-f-rule _⊔'_ -∞ sum ((map tails ∘ inits) xs) ℤ∞-⊔-is-monoid ⟩
(maximum ∘ map (maximum ∘ map sum) ∘ map tails ∘ inits) xs
≡⟨ cong maximum (map-o-rule tails (maximum ∘ map sum) (inits xs)) ⟩
(maximum ∘ map (maximum ∘ map sum ∘ tails) ∘ inits) xs
≡⟨ cong-app (cong (_∘_ maximum) (map-f-rule (hornor-rule-f _⊔'_ -∞ _+'_ (fin +0) ℤ∞-⊔-is-monoid ℤ∞-add-is-monoid distrib))) (inits xs) ⟩ -- ep = (fin +0) ?
(maximum ∘ map (foldl (λ a b → (a +' b) ⊔' (fin +0)) (fin +0)) ∘ inits) xs
≡⟨ cong maximum (scan-rule (λ a b → (a +' b) ⊔' (fin +0)) (fin +0) xs) ⟩
maximum (scanl (λ a b → (a +' b) ⊔' (fin +0)) (fin +0) xs)
≡⟨ refl ⟩
mss-fast xs
∎
derivation : mss ≡ mss-fast
derivation = extensionality prof