Skip to content

Commit 3142f3d

Browse files
authored
Merge pull request #56 from myoshi2891/dev-from-macmini
atcoder A72 - Tile Painting greedy algorithm Dev from macmini
2 parents 62eda20 + 5239a79 commit 3142f3d

6 files changed

Lines changed: 524 additions & 0 deletions

File tree

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"os"
7+
"sort"
8+
)
9+
10+
func max(a, b int) int {
11+
if a > b {
12+
return a
13+
}
14+
return b
15+
}
16+
17+
func main() {
18+
sc := bufio.NewScanner(os.Stdin)
19+
sc.Split(bufio.ScanLines)
20+
21+
sc.Scan()
22+
var H, W, K int
23+
fmt.Sscanf(sc.Text(), "%d %d %d", &H, &W, &K)
24+
25+
grid := make([][]rune, H)
26+
for i := 0; i < H; i++ {
27+
sc.Scan()
28+
row := []rune(sc.Text())
29+
grid[i] = row
30+
}
31+
32+
maxBlack := 0
33+
34+
// 全ての行選択パターンをビット列で列挙
35+
for bit := 0; bit < (1 << H); bit++ {
36+
paintedRows := []int{}
37+
for i := 0; i < H; i++ {
38+
if (bit>>i)&1 == 1 {
39+
paintedRows = append(paintedRows, i)
40+
}
41+
}
42+
43+
if len(paintedRows) > K {
44+
continue
45+
}
46+
47+
// gridのコピー(deep copy)
48+
painted := make([][]rune, H)
49+
for i := 0; i < H; i++ {
50+
painted[i] = make([]rune, W)
51+
copy(painted[i], grid[i])
52+
}
53+
54+
// 選んだ行を黒く塗る
55+
for _, row := range paintedRows {
56+
for j := 0; j < W; j++ {
57+
painted[row][j] = '#'
58+
}
59+
}
60+
61+
// 各列の黒マス数を数える
62+
blackCount := make([]int, W)
63+
for j := 0; j < W; j++ {
64+
for i := 0; i < H; i++ {
65+
if painted[i][j] == '#' {
66+
blackCount[j]++
67+
}
68+
}
69+
}
70+
71+
// gain を計算(白マスの多い列を貪欲に選ぶ)
72+
type gainCol struct {
73+
gain int
74+
col int
75+
}
76+
gains := []gainCol{}
77+
for j := 0; j < W; j++ {
78+
gains = append(gains, gainCol{H - blackCount[j], j})
79+
}
80+
sort.Slice(gains, func(i, j int) bool {
81+
return gains[i].gain > gains[j].gain
82+
})
83+
84+
// 残りの K - 行数 だけ列を塗る
85+
columnsToPaint := make(map[int]bool)
86+
remain := K - len(paintedRows)
87+
for i := 0; i < remain && i < len(gains); i++ {
88+
columnsToPaint[gains[i].col] = true
89+
}
90+
91+
// 黒マスの総数を数える
92+
total := 0
93+
for i := 0; i < H; i++ {
94+
for j := 0; j < W; j++ {
95+
if painted[i][j] == '#' || columnsToPaint[j] {
96+
total++
97+
}
98+
}
99+
}
100+
101+
maxBlack = max(maxBlack, total)
102+
}
103+
104+
fmt.Println(maxBlack)
105+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
const fs = require('fs');
2+
3+
const input = fs.readFileSync('/dev/stdin', 'utf8').trim().split('\n');
4+
const [H, W, K] = input[0].split(' ').map(Number);
5+
const grid = input.slice(1).map(line => line.split(''));
6+
7+
let maxBlack = 0;
8+
9+
for (let bit = 0; bit < (1 << H); bit++) {
10+
const paintedRows = [];
11+
for (let i = 0; i < H; i++) {
12+
if ((bit >> i) & 1) paintedRows.push(i);
13+
}
14+
const rowPaintCount = paintedRows.length;
15+
if (rowPaintCount > K) continue;
16+
17+
const painted = Array.from({ length: H }, (_, i) =>
18+
grid[i].slice()
19+
);
20+
21+
// 行を黒く塗る
22+
for (const row of paintedRows) {
23+
for (let j = 0; j < W; j++) {
24+
painted[row][j] = '#';
25+
}
26+
}
27+
28+
// 各列の黒マス数を数える
29+
const blackCountPerCol = Array(W).fill(0);
30+
for (let j = 0; j < W; j++) {
31+
for (let i = 0; i < H; i++) {
32+
if (painted[i][j] === '#') blackCountPerCol[j]++;
33+
}
34+
}
35+
36+
// 残りの操作回数で列を黒く塗る(貪欲に黒マスの増加が大きいものを選ぶ)
37+
const columnGain = [];
38+
for (let j = 0; j < W; j++) {
39+
const gain = H - blackCountPerCol[j];
40+
columnGain.push([gain, j]);
41+
}
42+
columnGain.sort((a, b) => b[0] - a[0]);
43+
44+
const columnsToPaint = new Set();
45+
for (let i = 0; i < K - rowPaintCount && i < columnGain.length; i++) {
46+
columnsToPaint.add(columnGain[i][1]);
47+
}
48+
49+
// 合計黒マス数を数える
50+
let totalBlack = 0;
51+
for (let i = 0; i < H; i++) {
52+
for (let j = 0; j < W; j++) {
53+
if (painted[i][j] === '#' || columnsToPaint.has(j)) {
54+
totalBlack++;
55+
}
56+
}
57+
}
58+
59+
maxBlack = Math.max(maxBlack, totalBlack);
60+
}
61+
62+
console.log(maxBlack);
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
list($H, $W, $K) = array_map('intval', explode(' ', trim(fgets(STDIN))));
4+
$grid = [];
5+
for ($i = 0; $i < $H; $i++) {
6+
$grid[] = str_split(trim(fgets(STDIN)));
7+
}
8+
9+
$maxBlack = 0;
10+
11+
for ($bit = 0; $bit < (1 << $H); $bit++) {
12+
$paintedRows = [];
13+
for ($i = 0; $i < $H; $i++) {
14+
if (($bit >> $i) & 1) {
15+
$paintedRows[] = $i;
16+
}
17+
}
18+
19+
$rowCount = count($paintedRows);
20+
if ($rowCount > $K) continue;
21+
22+
// グリッドのコピー
23+
$painted = [];
24+
foreach ($grid as $row) {
25+
$painted[] = $row;
26+
}
27+
28+
// 行を黒く塗る
29+
foreach ($paintedRows as $i) {
30+
for ($j = 0; $j < $W; $j++) {
31+
$painted[$i][$j] = '#';
32+
}
33+
}
34+
35+
// 各列の黒マス数をカウント
36+
$blackCount = array_fill(0, $W, 0);
37+
for ($j = 0; $j < $W; $j++) {
38+
for ($i = 0; $i < $H; $i++) {
39+
if ($painted[$i][$j] === '#') {
40+
$blackCount[$j]++;
41+
}
42+
}
43+
}
44+
45+
// 残りの操作回数で列を貪欲に塗る
46+
$gain = [];
47+
for ($j = 0; $j < $W; $j++) {
48+
$gain[] = ['gain' => $H - $blackCount[$j], 'col' => $j];
49+
}
50+
51+
usort($gain, function ($a, $b) {
52+
return $b['gain'] <=> $a['gain'];
53+
});
54+
55+
$columnsToPaint = [];
56+
$remainingOps = $K - $rowCount;
57+
for ($k = 0; $k < min($remainingOps, $W); $k++) {
58+
$columnsToPaint[$gain[$k]['col']] = true;
59+
}
60+
61+
// 黒マスを数える
62+
$totalBlack = 0;
63+
for ($i = 0; $i < $H; $i++) {
64+
for ($j = 0; $j < $W; $j++) {
65+
if ($painted[$i][$j] === '#' || isset($columnsToPaint[$j])) {
66+
$totalBlack++;
67+
}
68+
}
69+
}
70+
71+
$maxBlack = max($maxBlack, $totalBlack);
72+
}
73+
74+
echo $maxBlack . "\n";
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import sys
2+
from itertools import combinations
3+
4+
def main():
5+
input = sys.stdin.read
6+
data = input().strip().split('\n')
7+
8+
H, W, K = map(int, data[0].split())
9+
grid = [list(row) for row in data[1:]]
10+
11+
max_black = 0
12+
13+
for bit in range(1 << H):
14+
painted_rows = []
15+
for i in range(H):
16+
if (bit >> i) & 1:
17+
painted_rows.append(i)
18+
19+
row_count = len(painted_rows)
20+
if row_count > K:
21+
continue # 操作回数オーバー
22+
23+
# 行を黒く塗ったグリッドを作る
24+
painted = [row[:] for row in grid] # deepcopy
25+
for i in painted_rows:
26+
painted[i] = ['#'] * W
27+
28+
# 各列の黒マス数を数える
29+
black_count_per_col = [0] * W
30+
for j in range(W):
31+
for i in range(H):
32+
if painted[i][j] == '#':
33+
black_count_per_col[j] += 1
34+
35+
# 残りの K-row_count 回で最も gain の大きい列を選ぶ
36+
column_gain = []
37+
for j in range(W):
38+
gain = H - black_count_per_col[j] # 黒く塗れば gain だけ黒が増える
39+
column_gain.append((gain, j))
40+
41+
column_gain.sort(reverse=True)
42+
remaining_ops = K - row_count
43+
columns_to_paint = set()
44+
for i in range(min(remaining_ops, W)):
45+
columns_to_paint.add(column_gain[i][1])
46+
47+
# 最終的な黒マス数を数える
48+
total_black = 0
49+
for i in range(H):
50+
for j in range(W):
51+
if painted[i][j] == '#' or j in columns_to_paint:
52+
total_black += 1
53+
54+
max_black = max(max_black, total_black)
55+
56+
print(max_black)
57+
58+
if __name__ == "__main__":
59+
main()
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import * as fs from 'fs';
2+
3+
const input = fs.readFileSync('/dev/stdin', 'utf8').trim().split('\n');
4+
const [H, W, K] = input[0].split(' ').map(Number);
5+
const grid: string[][] = input.slice(1).map(line => line.split(''));
6+
7+
let maxBlack = 0;
8+
9+
for (let bit = 0; bit < (1 << H); bit++) {
10+
const paintedRows: number[] = [];
11+
for (let i = 0; i < H; i++) {
12+
if ((bit >> i) & 1) paintedRows.push(i);
13+
}
14+
15+
const rowPaintCount = paintedRows.length;
16+
if (rowPaintCount > K) continue;
17+
18+
// 塗り操作のコピー
19+
const painted: string[][] = grid.map(row => [...row]);
20+
21+
// 行を黒に塗る
22+
for (const row of paintedRows) {
23+
for (let j = 0; j < W; j++) {
24+
painted[row][j] = '#';
25+
}
26+
}
27+
28+
// 各列の黒マス数
29+
const blackCountPerCol: number[] = new Array(W).fill(0);
30+
for (let j = 0; j < W; j++) {
31+
for (let i = 0; i < H; i++) {
32+
if (painted[i][j] === '#') {
33+
blackCountPerCol[j]++;
34+
}
35+
}
36+
}
37+
38+
// 残り操作回数で列を貪欲に選ぶ
39+
const columnGain: [number, number][] = [];
40+
for (let j = 0; j < W; j++) {
41+
const gain = H - blackCountPerCol[j];
42+
columnGain.push([gain, j]);
43+
}
44+
45+
columnGain.sort((a, b) => b[0] - a[0]);
46+
47+
const columnsToPaint = new Set<number>();
48+
const remainingCols = K - rowPaintCount;
49+
for (let i = 0; i < Math.min(remainingCols, columnGain.length); i++) {
50+
columnsToPaint.add(columnGain[i][1]);
51+
}
52+
53+
// 黒マス合計を計算
54+
let totalBlack = 0;
55+
for (let i = 0; i < H; i++) {
56+
for (let j = 0; j < W; j++) {
57+
if (painted[i][j] === '#' || columnsToPaint.has(j)) {
58+
totalBlack++;
59+
}
60+
}
61+
}
62+
63+
maxBlack = Math.max(maxBlack, totalBlack);
64+
}
65+
66+
console.log(maxBlack);

0 commit comments

Comments
 (0)