В этом году главой Флатландии является Егор. Всег...
बनाया गया: 26 मार्च 2025
बनाया गया: 26 मार्च 2025
В этом году главой Флатландии является Егор. Всего во Флатландии проживает людей, каждый в своем доме. i-й дом находится в целочисленной точке (xi, yi).
Егор может выделить некоторые тройки людей. Требуется лишь, чтобы каждый человек относился не более, чем к одной тройке. Тройка людей считается счастливой, если треугольник, образованный их домами, является невырожденным (то есть три дома не находятся на одной прямой).
Помогите Егору определить, какого максимального количества счастливых троек можно добиться во Флатландии.
Формат входных данных
Первая строка содержит число n(3<=n<=300) — количество жителей во Флатландии.
i-я из следующих строчек содержит числа xi и yi (-10^9<=xi, yi<=10^9) — координаты дома, где проживает i-й человек.
Гарантируется, что никакие два дома не находятся в одной точке.
Формат выходных данных
Выведите одно число — максимальное количество счастливых троек, которого можно добиться во Флатландии.
Комментарий к примеру
В примере можно получить две счастливые тройки. Например, подойдет разбиение (1,1), (2,2), (1,4), и (6,3),(4,5), (4,1)
Примеры данных
ввод:
7
1 1
2 2
1 4
6 3
4 5
4 1
3 3
вывод:
2
ответ на языке go
gopackage main import ( "bufio" "fmt" "io" "math" "os" "strconv" ) // Функция быстрого ввода. func readInts(r *bufio.Reader) []int64 { line, err := r.ReadString('\n') if err != nil && err != io.EOF { panic(err) } fields := make([]int64, 0, 2) start := 0 for i := 0; i < len(line); i++ { if line[i] == ' ' || line[i] == '\n' { if start < i { num, _ := strconv.ParseInt(line[start:i], 10, 64) fields = append(fields, num) } start = i + 1 } } return fields } // Нахождение НОД (наибольшего общего делителя) неотрицательных чисел. func gcd(a, b int64) int64 { if b == 0 { return a } return gcd(b, a%b) } // Модуль (для int64). func abs(x int64) int64 { if x < 0 { return -x } return x } func main() { // Читаем вход. reader := bufio.NewReader(os.Stdin) line, _ := reader.ReadString('\n') n64, _ := strconv.ParseInt(line, 10, 64) n := int(n64) points := make([][2]int64, n) for i := 0; i < n; i++ { coords := readInts(reader) points[i][0] = coords[0] points[i][1] = coords[1] } // Если вдруг (хотя по условию n>=3). if n < 3 { fmt.Println(0) return } // Ищем наибольшее кол-во коллинеарных точек (k). // Алгоритм: для каждой точки считаем, сколько других лежит // на одной прямой со slope=(dx,dy). O(n^2). maxCollinear := 1 for i := 0; i < n; i++ { slopeCount := make(map[[2]int64]int) // Считаем направления от points[i] к остальным. for j := i + 1; j < n; j++ { dx := points[j][0] - points[i][0] dy := points[j][1] - points[i][1] // Нормализуем (dx, dy) чтобы учесть знак и сократить дробь. if dx < 0 { dx = -dx dy = -dy } else if dx == 0 && dy < 0 { // Вертикаль — сохраним как (0, 1), но с учётом знака dy. dy = -dy } g := gcd(abs(dx), abs(dy)) if g != 0 { dx /= g dy /= g } slopeCount[[2]int64{dx, dy}]++ } // наибольшее число точек, лежащих на прямой с точкой i, это localMax + 1 localMax := 0 for _, c := range slopeCount { if c > localMax { localMax = c } } if localMax+1 > maxCollinear { maxCollinear = localMax + 1 } } // Применяем формулу из анализа: // k = maxCollinear. // 1) Если все n точек коллинеарны, ответ 0 // 2) Если k = n-1, ответ 1 // 3) Если k = n-2, ответ зависит от n: // - если n >= 6, то 2 // - иначе 1 // 4) Иначе ответ floor(n/3) if maxCollinear == n { // Все точки коллинеарны fmt.Println(0) return } if maxCollinear == n-1 { // n-1 точка на одной прямой, одна снаружи fmt.Println(1) return } if maxCollinear == n-2 { if n >= 6 { fmt.Println(2) } else { // для n=4 или n=5 формируется не более 1 треугольника fmt.Println(1) } return } // Во всех остальных случаях: fmt.Println(n / 3) }
Пояснения к решению:
Так как n ≤ 300, описанное решение по времени работает достаточно быстро (O(n^2) на поиск максимального числа коллинеарных точек).