Haskell
import Data.Array
import qualified Data.Map as M
import qualified Data.Set as S
data Dir = L | R | U | D
solve g = unzip $ prices $ findRegions 1 g h (indices g)
where h = listArray (bounds g) (repeat 0)
prices g = [ (x * y, x * z) | (i,x) <- M.assocs xs, let y = ys M.! i, let z = zs M.! i ]
where xs = areas g
ys = perimeters isFence g
zs = perimeters isSide g
areas g = M.fromListWith (+) $ zip (elems g) (repeat 1)
perimeters f g = M.fromListWith (+) [ (x,1) | (i,x) <- assocs g, dir <- [L,R,U,D], f g i dir ]
isFence g (r,c) dir = case dir of
L -> c == c0 || x /= g ! (r,c-1)
R -> c == c1 || x /= g ! (r,c+1)
U -> r == r0 || x /= g ! (r-1,c)
D -> r == r1 || x /= g ! (r+1,c)
where x = g ! (r,c)
((r0,c0),(r1,c1)) = bounds g
isSide g (r,c) dir = isFence g (r,c) dir && case dir of
L -> r == r0 || noFence (r-1,c)
R -> r == r1 || noFence (r+1,c)
U -> c == c0 || noFence (r,c-1)
D -> c == c1 || noFence (r,c+1)
where noFence i = x /= g ! i || not (isFence g i dir)
x = g ! (r,c)
((r0,c0),(r1,c1)) = bounds g
findRegions _ _ h [] = h
findRegions i g h (x:xs)
| h ! x == 0 = findRegions (i+1) g h1 xs
| otherwise = findRegions i g h xs
where h1 = h // zip (bfs g S.empty [x]) (repeat i)
bfs _ _ [] = []
bfs g seen (x:xs)
| x `S.member` seen = bfs g seen xs
| otherwise = x : bfs g (x `S.insert` seen) (xs ++ next g x)
next g x@(r,c) = filter valid [(r-1,c),(r,c+1),(r+1,c),(r,c-1)]
where valid y = inRange (bounds g) y && g ! y == g ! x
readGrid xss = listArray ((1,1),(h,w)) $ concat xss
where h = length xss
w = length $ head xss
main = do g <- readGrid . lines <$> readFile "input"
let (xs,ys) = solve g
print $ sum xs
print $ sum ys