[Question]
  [
You are given an \$ 25 \times 25 \$ square lattice graph. You are to remove certain nodes from the graph as to *minimize* your score, based on the following scoring system:
Your score will be the \$ \text{number of nodes removed} \$ \$ + \$ the \$ \text{size of the largest connected component} \$. In the smaller \$ 4 \times 4 \$ example below, exactly \$ 5 \$ nodes have been crossed out (removed), and the size of the largest connected component is \$ 4 \$ (top and left components). Therefore the total score is \$ 9 \$.
[![Square lattice graph](https://i.stack.imgur.com/AQXtv.png)](https://i.stack.imgur.com/AQXtv.png)
## Notes
* You should give your score alongside a list of crossed out nodes
* If a program was written to solve this problem, please include it in your answer if possible
* [Here](https://tio.run/##bVHLTsMwELz7K0bi0ISmVls4VQSJCyeOHCJFETKJ07hqN5HjQPn6snaaIqAHv2Z2Z3bX3ZdrWlqfTjd4MaSx2uAJNBzetQUlqDS1ztAWikA48tpaU4lz8B2kZGjuswhlo6wqnbY9WoJWZYO9j7pouEaHdEQzOUPdskNb6QSzbHyVtu17XS3awQUmFoKQwpCLrPp8M9QNLopjsbWqaxJ8mJ7ZvEh4CZ9vOBRW0VZHFG8EQpxUXaepivam/y0TC68w0fmz2ve6wC2IbStdo6r7yCYovZKpYfGAJdjF4jHlbn29E1ReoGCZ2yIvC6Rp6IxR9hkxloLVbrCEpfiBuY1XO2gxccHaj9Xb8zmV4qHLG4v//GLkV0Io6lcsy8eaj@XV@Xhs9wfzrY5NmCLfjU3wZymq@EtcKDkQPhRnk4M6Rv6ahEJMgp0f7jWlbDblrTFPuc7O8u@OOvMAn073IpNSCpnJTEje/U1@Aw) is a program to check your score
This is [code-challenge](/questions/tagged/code-challenge "show questions tagged 'code-challenge'"), so the *minimum* score wins!
  
[Answer]
# 92+41=133
```
.......X.........X.......
........X.......X........
.......X.........X.......
......X.X.......X.X......
.....X...X.....X...X.....
....X.....X...X.....X....
...X.......X.X.......X...
X.X.........X.........X.X
.X.X.......X.X.......X.X.
....X.....X...X.....X....
.....X...X.....X...X.....
......X.X.......X.X......
.......X.........X.......
......X.X.......X.X......
.....X...X.....X...X.....
....X.....X...X.....X....
.X.X.......X.X.......X.X.
X.X.........X.........X.X
...X.......X.X.......X...
....X.....X...X.....X....
.....X...X.....X...X.....
......X.X.......X.X......
.......X.........X.......
........X.......X........
.......X.........X.......
```
Now with 13 regions, all of 41.
# Previous version 93+46=139
```
X...........X...........X
.X..........X..........X.
..X.........X.........X..
...X.......X.X.......X...
....X.....X...X.....X....
.....X...X.....X...X.....
......X.X.......X.X......
.......X.........X.......
......X.X.......X.X......
.....X...X.....X...X.....
....X.....X...X.....X....
...X.......X.X.......X...
XXX.........X.........XXX
...X.......X.X.......X...
....X.....X...X.....X....
.....X...X.....X...X.....
......X.X.......X.X......
.......X.........X.......
......X.X.......X.X......
.....X...X.....X...X.....
....X.....X...X.....X....
...X.......X.X.......X...
..X.........X.........X..
.X..........X..........X.
X...........X...........X
```
8 regions of 46, 4 regions of 41.
[Answer]
# Lower bound: 114
**Notation:** Add 25 points to each side of the grid to produce a 27-by-27 grid with corners missing. Call these additional 100 points \$\mathcal{E}\$. Let \$\mathcal{X}\$ denote the set of deleted points. Say the \$i\$th component has \$c\_i\$ points and is bounded by \$x\_i\$ members of \$\mathcal{X}\$ and by \$e\_i\$ members of \$\mathcal{E}\$.
**Constraints:** First, components that border \$\mathcal{E}\$ border disjoint subsets of \$\mathcal{E}\$, and so
$$\sum\_i e\_i \leq 100.$$
Next, consider the simple polygon with vertices/perimeter at the members of \$\mathcal{X}\$ and \$\mathcal{E}\$ that border the \$i\$th component. By [Pick's theorem](https://en.wikipedia.org/wiki/Pick%27s_theorem), the area of this polygon is
$$A\_i=c\_i + \frac{x\_i + e\_i}{2} - 1.$$
Meanwhile, the octagon with \$\mathcal{E}\$ as vertices/perimeter has area 674. As such,
$$\sum\_i c\_i + \sum\_i\Big( \frac{ x\_i + e\_i }{2} - 1 \Big)
= \sum\_i A\_i
\leq 674.$$
Furthermore, it is [conjectured](https://oeis.org/A261491) (!) that
$$\frac{ x\_i + e\_i }{2} - 1
\geq \frac{1}{2}\Big\lceil \sqrt{8c\_i-4}\Big\rceil.$$
**Optimization:** In our notation, we seek to minimize \$|\mathcal{X}|+\max\_i c\_i\$. It is convenient to write
$$|\mathcal{X}|
= 625 - \sum\_i c\_i.$$
We may relax our optimization to only consider the above constraints:
$$\text{minimize} \quad 625 - \sum\_i c\_i + \max\_i c\_i$$
$$\text{subject to} \quad \sum\_i e\_i \leq 100, \quad
\sum\_i c\_i + \sum\_i\Big( \frac{ x\_i + e\_i }{2} - 1 \Big) \leq 674, $$
$$\frac{ x\_i + e\_i }{2} - 1
\geq \frac{1}{2}\Big\lceil \sqrt{8c\_i-4}\Big\rceil, \quad x,c,e \geq 0.$$
The square root makes this optimization a pain, so we further relax to a sequence of linear programs. To accomplish this, we take
$$X\_k := \sum\_{i:c\_i=k} x\_i,
\quad
E\_k := \sum\_{i:c\_i=k} e\_i,
\quad
z\_k := |\{i:c\_i = k\}|,
\quad
C := \max\_i c\_i.$$
Then for each \$C\in\{1,\ldots,133\}\$, we solve the linear program
$$\text{minimize} \quad 625 - \sum\_k kz\_k + C$$
$$\text{subject to} \quad \sum\_k E\_k \leq 100, \quad
\sum\_k kz\_k + \sum\_k\Big( \frac{ X\_k + E\_k }{2} - z\_k \Big) \leq 674, $$
$$\frac{ X\_k + E\_k }{2} - z\_k
\geq \frac{1}{2}\Big\lceil \sqrt{8k-4}\Big\rceil\cdot z\_k, \quad X,E,z \geq 0.$$
Indeed, we only need to consider \$C\leq 133\$ thanks to [the best known solution](https://codegolf.stackexchange.com/a/204368/85259). Here's an implementation in MATLAB using [CVX](http://cvxr.com/cvx/):
```
vals=[];
for C=1:133;
    [C min(vals)]
    w = ceil(sqrt(8*(1:C)-4))/2;
    cvx_begin quiet
        variable X(C) 
        variable E(C) 
        variable z(C) 
        minimize( 625 - (1:C)*z + C )
        subject to
            sum(E) <= 100
            (1:C)*z + sum( (X+E)/2-z ) <= 674
            for ii=1:C
                (X(ii)+E(ii))/2-z(ii) >= w(ii)*z(ii)
            end
            X >= 0
            E >= 0
            z >= 0
        cvx_end
    vals(end+1)=cvx_optval;
end
```
The minimum value of 113.32 occurs when \$C=41\$. (Curiously, this is the size of the components in [the best known solution](https://codegolf.stackexchange.com/a/204368/85259).) Here's a plot of how the minimum varies with \$C\$:
![](https://i.stack.imgur.com/vFEC4.png)
[Answer]
## Score 80 + 61 = 141
```
........X...........X....
.......X.............X...
........X...........X....
.X.......X.........X.....
X.X.......X.......X......
...X.......X.....X.......
....X.......X...X........
.....X.....X.X.X.......X.
......X...X...X.......X.X
.......X.X.....X.....X...
........X.......X...X....
.......X.........X.X.....
......X...........X......
.....X.X.........X.......
....X...X.......X........
...X.....X.....X.X.......
X.X.......X...X...X......
.X.......X.X.X.....X.....
........X...X.......X....
.......X.....X.......X...
......X.......X.......X.X
.....X.........X.......X.
....X...........X........
...X.............X.......
....X...........X........
```
Found with the help of [this program](https://tio.run/##lVFdS8MwFH1ufkWoL7dQiw6G4J4UFBzbHM5BXsvM2rCsmW0zBNlvr7drtzbNKhoaem/O/TrnruIwXalQFsVU7TncL3cTvs69EXlUXzC482l53SsXX@Y6i0H7dMKTKI9hzvnmQUrwPMTWKqUwGHr0mzhjvd29K7jxqUDEOUIvyU7nizwVSYQJVKwpPH3qUGawwfLMxbc5gjlsvBHlMuO0GudNRHE5zeHcfSoSnYE1g08Xegv6T8PUUOXMVA6v6YdIQnksV/KpYOdZYGk3KLmj948BHOeA12SATwdSTzPjUZhzuMWk2hyUaZUCCylWHMZKJGU3Fz8MGyJeFEF9WNCco00uAJVHfslhFlRZhFlQ/SfW08kj3ehzUWJEt0sTM7oBWMOHdXpZfFi/Bqds0qNAM1tXgRYfSyTS4d5kd3Rj7T4tcka2wYf175TZO7V3xMjFfZ61vqCAudOgf6eGXVzv5Q8 "Charcoal – Try It Online") which tells you the number of `X`s and the size of each area of `.`s.
## Previous score 89 + 54 = 143
```
....X...............X....
.....X.............X.....
......X...........X......
.......X.........X.......
........X...X...X........
.........XXX.XXX.........
........X.......X........
.......X.........X.......
XXXXXXX...........XXXXXXX
.......X.........X.......
.......X.........X.......
........X.......X........
.........XXXXXXX.........
........X.......X........
.......X.........X.......
.......X.........X.......
XXXXXXX...........XXXXXXX
.......X.........X.......
........X.......X........
.........XXX.XXX.........
........X...X...X........
.......X.........X.......
......X...........X......
.....X.............X.....
....X...............X....
```
[Answer]
# C++, score 147
Adding simulated annealing has changed the results *very significantly*. They are now extremely worrying.
The code:
```
//#define _GLIBCXX_DEBUG
#include <x86intrin.h>
#include <iostream>
#include <streambuf>
#include <bitset>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <climits>
#include <random>
#include <set>
#include <list>
#include <map>
#include <unordered_map>
#include <deque>
#include <stack>
#include <queue>
#include <string>
#include <iomanip>
#include <unordered_set>
#include <thread>
std::mt19937_64 mt;
int N = 25;
std::vector<char> cuts(N*N);
std::vector<char> marks;
int dfs(int at)
{
    char x = at % N, y = at / N;
    marks[at] = true;
    int sz = 1;
    static const char ddx[4] {1, -1, 0, 0};
    static const char ddy[4] {0, 0, 1, -1};
    for(int d = 0; d < 4; d++)
    {
        int dx = ddx[d], dy = ddy[d];
        int nx = x + dx, ny = y + dy;
        if(nx < 0 || ny < 0 || ny >= N || nx >= N) continue;
        if(marks[ny * N + nx]) continue;
        sz += dfs(ny * N + nx);
    }
    return sz;
}
bool connected(int at)
{
    char x = at % N, y = at / N;
    static const char ddx[4] {1, -1, 0, 0};
    static const char ddy[4] {0, 0, 1, -1};
    for(int d = 0; d < 4; d++)
    {
        int dx = ddx[d], dy = ddy[d];
        int nx = x + dx, ny = y + dy;
        if(nx < 0 || ny < 0 || ny >= N || nx >= N) continue;
        if(cuts[ny * N + nx]) return true;
    }
    return false;
}
int score()
{
    marks = cuts; //true -> pretend it's already cut
    int ans1 = 0, ans2 = 0;
    for(char el : cuts) ans2 += el == true;
    for(int i = 0; i < N*N; i++)
    {
        if(marks[i]) continue;
        ans1 = std::max(ans1, dfs(i));
    }
    return ans1 + ans2;
}
int main()//int64_t argc, char*argv[])
{
    int gs = 8;
    for(int y = 0; y < N; y++)
    for(int x = 0; x < N; x += gs)
        cuts[y*N+x] ^= true;
    for(int y = 0; y < N; y += gs)
    for(int x = 0; x < N; x++)
        cuts[y*N+x] ^= true;
    for(int x = 0; x < N; x++)
        cuts[x] ^= true,
        cuts[N*x] ^= true,
        cuts[N*(N-1)+x] ^= true,
        cuts[N*x+N-1] ^= true;
    //do random changes, minimizing score
    printf("%d\n", score());
    int its = 1e6;
    float temp = 1;
    for(int y = 0; y < N; y++)
    {
        for(int x = 0; x < N; x++) printf("%c", cuts[y*N+x] ? '#' : '.');
        printf("\n");
    }
    while(its --> 0)
    {
        if(its % 1000 == 0) printf("i: %d\n", its);
        temp -= 2e-6;
        int i = 0;
        do { i = mt() % (N*N); }
        while(!cuts[i] && !connected(i));
        //fun fact: do..while loops don't actually need braces
        int sb = score();
        cuts[i] ^= 1;
        int sa = score();
        int delta = sb - sa; //positive -> good
        //printf("%d\n", delta);
        if(delta <= 0 && (temp <= 0 || ldexpf(std::exp(delta / temp), 60) < mt()))
            cuts[i] ^= 1;
        else printf("%d\n", sa);
    }
    for(int y = 0; y < N; y++)
    {
        for(int x = 0; x < N; x++) printf("%c", cuts[y*N+x] ? '#' : '.');
        printf("\n");
    }
}
```
The output, with the starting condition being a 3x3 grid:
```
........#........#.......
.........#......#........
........#.......#........
.......#.......#.........
........#.......#........
........#........#.......
.......#........#........
.#....#.#......#.#...#.##
#.#.##...#...##...#.#.#..
...#......#.#....#.#.....
...........#.....#.......
..........#......#.......
.........#.......#.......
#......##........#.......
.#....#.......###........
..##.#.......#..#........
....#......##....#....#.#
.....#....#......#...#.#.
......#.##........###....
.......#.........#.......
.......#........#........
........#......#.........
.......#......#..........
.......#......#..........
.......#.....#...........
```
```
[Answer]
# Score: ~~158 145~~ 141
*-4 thanks to @LevelRiverSt !*
```
.....X.............X.....
.....X.............X.....
......X...........X......
.......X.........X.......
........X.......X........
XX.......X.....X.......XX
..X.......X.X.X.......X..
...X.......X.X.......X...
....X.....X...X.....X....
.....X...X.....X...X.....
......X.X.......X.X......
.......X.........X.......
......X...........X......
.......X.........X.......
......X.X.......X.X......
.....X...X.....X...X.....
....X.....X...X.....X....
...X.......X.X.......X...
..X.......X.X.X.......X..
XX.......X.....X.......XX
........X.......X........
.......X.........X.......
......X...........X......
.....X.............X.....
.....X.............X.....
```
[Try it online!](https://tio.run/##nVLBjpswEL37K57UQ6AhKEnVS1RW2ktPPfaAhFDlghMcZQdkTLv9@nRsAkuyoasukmX7vZn3ZsY0f2xV0/Z8/oBvmhQ2OzyCuqefyoAilIpqq@kASSA88zoYXYpL8CfEMUNLl0UoKmlkYZVpUROULCqcXNSoYSvl0xEs4gX2NTvUpYqwSPtbYeq2VeWq7qxnQiEICTTZwMjfPzQ1nQ3CUByMbKoIv3TLbJZHvITL1xwKI@mgAgp3Aj4ulk2jqAxOur2WCYVTGOjsqzy1KsdHENuWao9y3wYmQuGU9B4GX7AGuxg8JNytq3eAihHylpnJsyJHkvjOGGWfHmMpGGU7Q1iLF5jb@G46JQbOW7uxOnveh1IcNN6xes2ven4jhKR2w7K8bXlb352Pw443mGu1b0Ln2bFvgh9LUslPYn3JnnChsCztvHWEY@iAi@uTfA7cMYIN70umi90lfotlwgU3hp@5z196eIJEHjift59F7L40nn797S3mirqcRXxLDSdxC4whIr2GxlsqptHpNFPE19RLvrgWmkiKO@BNP68k3@znPTOY9Zmtbbaf2RnMze1fs557n3fP4P/@qr8)
**Number of X**: 80  
**Largest component**: 61
Divide the grid into 9 rougly equal areas of size ~60.
[Answer]
# 92 + 45 = 137
```
......X.........X........
.......X........X........
........X........X.......
.......X.X.......X.......
......X..X......X.X......
.....X....X....X...X.....
....X......X..X.....X...X
X..X.......X.X.......X.X.
.XX.........X.........X..
...X.......X.X.......X...
....X.....X...X.....X....
.....X...X.....X...X.....
......X.X.....X.X.X......
.......X.....X...X.......
......X.....X.....X......
.....X......X......X.....
....X......X........X....
....X.....X.X........XXX.
XXXX.X...X...X......X...X
......X.X.....X....X.....
.......X.......X..X......
.......X........XX.......
........X.......X........
........X.......X........
........X.......X........
```
[Try it online!](https://tio.run/##jVJNj5swEL37V4zUQ6AhKEm1l6istJeeeuzBEkKVC05wlB2QMe3216djE74MkYoENu/NzJs3dv3XlBUe7/dP8F2hhMMJ3gDb919SA0ZQSKyMwgsIBIQPei9aFewR/AXimKCtzULIS6FFbqRuoEKQIi/hZqOGGqaULh2CTbyBc0UKVSEj2PDuL9dV08hiV7XGMSFjCAkoNIEWf34qrFsThCG7aFGXEfxWDbFpFtHLbL6iUNACLzLA8MTAxcWiriUWwU018zIhsxV6Ov0mbo3M4DMgyRbyDMW5CXQEua2kzqDhK@yBVDS8JuTW9ttD@QA5yVRnaZ5BkjhnhJJOh1Ep0NK0GmHPRphs/NCtZD3npO1YrTytfSsWGv5ht@R3HX9gTGBzoLK0HGnZr87HYlcPs1Y7EypLr50JOiyBBR2JcS07woZCXrVoqLzVV9E1tNhD@F18BHYbdUHhemW@OT1yjrBNqO9a02l3NbYOvt@PLyx2D4/7Z9gxH1gwS2rM4esMH5AhhI1xw4ePDPcSHc3GOjMtTjl8xYvdsXg9Z6bDZ7tJbz7N5oW472eZMZ2B953OwFvYkpj2xj075J5mwO2Xz9W7ufld@36mc@HP7gF/dg@e35D/Yf4B "Python 2 – Try It Online")
I started with a program, then I took the best output and hand-modified it to get this. Next I'm going to try restricting the program to only place Xs on one color of squares - that seems like it might work better. The program is written in rust. The key idea was to seed the map with a Vornoi diagram before running a simplified simulating annealing:
```
use rand::prelude::*;
use std::collections::{HashMap, HashSet};
fn make_neighbors(point: (usize, usize), size: usize) -> Vec<(usize, usize)> {
    let (r, c) = point;
    let mut neighbors = vec![];
    if r > 0 {
        neighbors.push((r - 1, c));
    }
    if c > 0 {
        neighbors.push((r, c - 1));
    }
    if r < size - 1 {
        neighbors.push((r + 1, c));
    }
    if c < size - 1 {
        neighbors.push((r, c + 1));
    }
    neighbors
}
fn value_board(board: &Vec<Vec<bool>>) -> usize {
    let size = board.len();
    let mut color_counts = vec![];
    let mut removed_count = 0;
    let mut seen = HashSet::new();
    for r in 0..size {
        for c in 0..size {
            if board[r][c] {
                removed_count += 1;
            } else {
                let mut color_count = 0;
                let mut flood_stack = vec![(r, c)];
                while !flood_stack.is_empty() {
                    let point = flood_stack.pop().unwrap();
                    if !board[point.0][point.1] &&!seen.contains(&point) {
                        seen.insert(point);
                        color_count += 1;
                        let neighbors = make_neighbors(point, size);
                        flood_stack.extend(neighbors);
                    }
                }
                color_counts.push(color_count);
            }
        }
    }
    let max_color_count = color_counts.into_iter().max().unwrap_or(0);
    removed_count + max_color_count
}
// TODO: make removed, neighbor_removed into VecSets.
fn simulated_annealing(input_board: &Vec<Vec<bool>>, max_steps: usize) -> Vec<Vec<bool>> {
    let size = input_board.len();
    let mut coloring: HashMap<(usize, usize), usize> = HashMap::new();
    let mut max_color = 0;
    let mut color_counts = vec![];
    let mut removed: Vec<(usize, usize)> = vec![];
    let mut neighbor_removed: Vec<(usize, usize)> = vec![];
    let mut board = input_board.clone();
    for r in 0..size {
        for c in 0..size {
            if board[r][c] {
                removed.push((r, c));
                let neighbors = make_neighbors((r, c), size);
                for point in neighbors {
                    if !board[point.0][point.1] && !neighbor_removed.contains(&point) {
                        neighbor_removed.push(point);
                    }
                }
            } else {
                if !coloring.contains_key(&(r, c)) {
                    let color = max_color;
                    max_color += 1;
                    color_counts.push(0);
                    let mut flood_stack = vec![(r, c)];
                    while !flood_stack.is_empty() {
                        let point = flood_stack.pop().unwrap();
                        if !board[point.0][point.1] && !coloring.contains_key(&point) {
                            coloring.insert(point, color);
                            color_counts[color] += 1;
                            let neighbors = make_neighbors(point, size);
                            flood_stack.extend(neighbors);
                        }
                    }
                }
            }
        }
    }
    let mut rng = thread_rng();
    for step in 0..max_steps {
        //dbg!(&removed, &neighbor_removed, &coloring, &board);
        assert_eq!(removed.len() + coloring.len(), size.pow(2));
        if rng.gen::<f64>() < 0.5  && !removed.is_empty() {
            let index = rng.gen_range(0, removed.len());
            let &(r, c) = &removed[index];
            assert!(removed.contains(&(r, c)));
            assert!(!neighbor_removed.contains(&(r, c)));
            assert!(!coloring.contains_key(&(r, c)));
            assert!(board[r][c]);
            let neighbors = make_neighbors((r, c), size);
            let neighbor_colors: HashSet<usize> = neighbors
                .iter()
                .filter_map(|n| coloring.get(n))
                .cloned()
                .collect();
            // Remove if only 1 color.
            // This will always be a neutral or improving step
            // Never remove otherwise
            if neighbor_colors.len() <= 1 {
                board[r][c] = false;
                removed.swap_remove(index);
                let neighbors = make_neighbors((r, c), size);
                for neighbor in neighbors {
                    if board[neighbor.0][neighbor.1] {
                        neighbor_removed.push((r, c));
                        break;
                    }
                }
                let new_color = if neighbor_colors.len() == 1 {
                    neighbor_colors.into_iter().next().unwrap()
                } else {
                    let new_color = max_color;
                    max_color += 1;
                    color_counts.push(0);
                    new_color
                };
                coloring.insert((r, c), new_color);
                color_counts[new_color] += 1;
            }
        } else if !neighbor_removed.is_empty() {
            let index = rng.gen_range(0, neighbor_removed.len());
            let (r, c) = neighbor_removed[index];
            let my_color = *coloring.get(&(r, c)).unwrap();
            let is_max_color = color_counts.iter().enumerate().all(|(i, &color_count)| {
                i == my_color || color_count < color_counts[my_color]
            });
            // Flip if either is a max color, in which case it's free,
            // or temp is high enough and get lucky.
            let take_action = is_max_color || {
                step < max_steps / 2 && rng.gen::<f64>() < 0.1
            };
            if take_action {
                board[r][c] = true;
                neighbor_removed.swap_remove(index);
                removed.push((r, c));
                coloring.remove(&(r, c));
                color_counts[my_color] -= 1;
                let neighbors = make_neighbors((r, c), size);
                for neighbor in neighbors {
                    if !board[neighbor.0][neighbor.1] && !neighbor_removed.contains(&neighbor) {
                        neighbor_removed.push(neighbor)
                    }
                }
            }
        }
    }
    board
}
// Given starting points and a board size, make a vornoi diagram
fn vornoi(points: &Vec<(usize, usize)>, size: usize) -> Vec<Vec<bool>> {
    let mut time_board: Vec<Vec<Option<usize>>> = vec![vec![None; size]; size];
    let mut board = vec![vec![false; size]; size];
    for (i, point) in points.iter().enumerate() {
        time_board[point.0][point.1] = Some(i);
    }
    for _ in 0..size {
        let mut new_board = time_board.clone();
        for r in 0..size {
            for c in 0..size {
                if let Some(i) = time_board[r][c] {
                    let neighbors = make_neighbors((r, c), size);
                    for (nr, nc) in neighbors {
                        if let Some(j) = new_board[nr][nc] {
                            if i != j {
                                board[r][c] = true;
                            }
                        } else {
                            new_board[nr][nc] = Some(i);
                        }
                    }
                }
            }
        }
        time_board = new_board
    }
    board
}
fn random_vornoi(num_points: usize, size: usize) -> Vec<Vec<bool>> {
    let mut points = vec![];
    let mut rng = thread_rng();
    while points.len() < num_points {
        let r = rng.gen_range(0, size);
        let c = rng.gen_range(0, size);
        if !points.contains(&(r, c)) {
            points.push((r, c))
        }
    }
    vornoi(&points, size)
}
fn print_board(board: &Vec<Vec<bool>>) {
    let string_board = board
        .iter()
        .map(|row| {
            row.iter()
                .map(|&c| if c { 'X' } else { '.' })
                .collect::<String>()
        })
        .collect::<Vec<String>>()
        .join("\n");
    println!("{}", string_board);
}
fn main() {
    let size: usize = 25;
    let reps = 100;
    let steps = 30000000;
    let mut best_points = 0;
    let mut best_board = None;
    let mut best_value = size.pow(2);
    for num_points in 8..17 {
        let mut best_board_points = None;
        let mut best_value_points = size.pow(2);
        for _ in 0..reps {
            let board = random_vornoi(num_points, size);
            let better_board = simulated_annealing(&board, steps);
            let value = value_board(&better_board);
            if value < best_value {
                best_board = Some(better_board.clone());
                best_value = value;
                best_points = num_points;
            }
            if value < best_value_points {
                best_board_points = Some(better_board);
                best_value_points = value;
            }
        }
        println!("{} {}", num_points, best_value_points);
        print_board(&best_board_points.unwrap());
        println!();
    }
    println!("{} {}", best_points, best_value);
    print_board(&best_board.unwrap());
    println!();
}
```
To run the program, put the above file in `src/main.rs` and put `rand = "*"` in your Cargo.toml.
[Answer]
# Score: ~~314~~ 313
-1 thanks to @Level River St
```
.X.X.X.X.X.X.X.X.X.X.X.X.
X.X.X.X.X.X.X.X.X.X.X.X.X
.X.X.X.X.X.X.X.X.X.X.X.X.
X.X.X.X.X.X.X.X.X.X.X.X.X
.X.X.X.X.X.X.X.X.X.X.X.X.
X.X.X.X.X.X.X.X.X.X.X.X.X
.X.X.X.X.X.X.X.X.X.X.X.X.
X.X.X.X.X.X.X.X.X.X.X.X.X
.X.X.X.X.X.X.X.X.X.X.X.X.
X.X.X.X.X.X.X.X.X.X.X.X.X
.X.X.X.X.X.X.X.X.X.X.X.X.
X.X.X.X.X.X.X.X.X.X.X.X.X
.X.X.X.X.X.X.X.X.X.X.X.X.
X.X.X.X.X.X.X.X.X.X.X.X.X
.X.X.X.X.X.X.X.X.X.X.X.X.
X.X.X.X.X.X.X.X.X.X.X.X.X
.X.X.X.X.X.X.X.X.X.X.X.X.
X.X.X.X.X.X.X.X.X.X.X.X.X
.X.X.X.X.X.X.X.X.X.X.X.X.
X.X.X.X.X.X.X.X.X.X.X.X.X
.X.X.X.X.X.X.X.X.X.X.X.X.
X.X.X.X.X.X.X.X.X.X.X.X.X
.X.X.X.X.X.X.X.X.X.X.X.X.
X.X.X.X.X.X.X.X.X.X.X.X.X
.X.X.X.X.X.X.X.X.X.X.X.X.
```
The largest connected component is of size 1.
Verify the score here: [Try it online!](https://tio.run/##7VGxTsMwFNz9FScxNKFp1BaxVASJhYmRIVIUIZO4jav2JXIcKF8fnh1SBLQbYxVZju/e3b1nNx@2qmnZ91d40qSwWOEB1O1flQFFKBXVVtMGkkA48NoYXYqv4hvEMUNTpyIUlTSysMq0qAlKFhV2ruroYSvl5Qgm8QTrmhPqUkWYpMOpMHXbqnJWd9YzoRCEBJpsYOT7i6ams0EYio2RTRXhTbfMZnnESzi95lIYSRsVULgS8HWxbBpFZbDT7U@bUDiHkc4e5a5VOa5BHFuqNcp1G5gIhXPSaxjcYQ5OMbhPeFrX7wgVR8hHZibPihxJ4idjlHMGjK1glO0MYS6@YR7j2XRKjJyPdtfq4nkfW3HQ8YzZX3428AshJLULtuVtydv85P04bPsLc6MOQ@g82w5D8GNJKvlJrG/ZE64UXyF7eQjcb@Qb0RG27nJPOaWTUbfENOE@G8OvO/hMPdz3y1sRp2c@cY5IL5qL5v81nw "Python 2 – Try It Online")
]