Перескающиеся прямоугольники
Всем привет
Решаю такую задачу:
Пусть для каждого прямоугольника заданы:
1. Уникальная метка прямоугольника, например "#123",
2. Расстояние от левого и верхнего края картины, например "3,2",
3. Ширина и высота прямоугольника, например "5x4",
Таким образом, запись "#123 @ 3,2: 5x4" означает, прямоугольник #123 расположен в 3см от левого края, в 2см от верхнего края, имеет 5см в ширину и 4см в высоту.
1)Найти суммарную площадь пересечений (считая каждое пересечение 1 раз)
2)Как оказалось, ровно 1 прямоугольник не пересекается ни с одним другим. Найдите его и выведите метку.
Написал код для решения:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp5
{
class Program
{
struct rectangle
{
public int _id;
public int _x_left, _y_left;
public int _x_right, _y_right;
public bool _crossing;
}
static int _sum_of_crossing(List<rectangle> _main_list)
{
int _answer_count = 0;
for (int i = 0; i < _main_list.Count - 1; i++)
{
for (int k = i + 1; k < _main_list.Count; k++)
{
List<int> list_of_X = new List<int>();
List<int> list_of_Y = new List<int>();
list_of_X.Add(_main_list[i]._x_left);
list_of_X.Add(_main_list[i]._x_right);
list_of_X.Add(_main_list[k]._x_left);
list_of_X.Add(_main_list[k]._x_right);
list_of_Y.Add(_main_list[i]._y_left);
list_of_Y.Add(_main_list[i]._y_right);
list_of_Y.Add(_main_list[k]._y_left);
list_of_Y.Add(_main_list[k]._y_right);
if (list_of_X[0] >= list_of_X[3] || list_of_X[2] >= list_of_X[1]
|| list_of_Y[3] <= list_of_Y[0] || list_of_Y[1] <= list_of_Y[2])
{
continue;
}
list_of_X.Sort();
list_of_Y.Sort();
_answer_count += (list_of_X[1] - list_of_X[2]) * (list_of_Y[1] - list_of_Y[2]);
var temp = _main_list[i];
temp._crossing = true;
_main_list[i] = temp;
temp = _main_list[k];
temp._crossing = true;
_main_list[k] = temp;
}
}
return _answer_count;
}
static void Main(string[] args)
{
List<rectangle> _main_list = new List<rectangle>();
string _input_line = " ";
while (!string.IsNullOrEmpty(_input_line))
{
_input_line = Console.ReadLine();
if (string.IsNullOrEmpty(_input_line))
break;
string[] splitted = _input_line.Split('#', '@', ',', ':', 'x');
rectangle _item;
_item._id = Convert.ToInt32(splitted[1]);
_item._x_left = Convert.ToInt32(splitted[2].Trim());
_item._y_left = Convert.ToInt32(splitted[3]);
_item._x_right = Convert.ToInt32(splitted[4].Trim()) + _item._x_left;
_item._y_right = Convert.ToInt32(splitted[5]) + _item._y_left;
_item._crossing = false;
_main_list.Add(_item);
}
Console.WriteLine(_sum_of_crossing(_main_list));
Console.WriteLine();
for (int i = 0; i < _main_list.Count; i++)
{
if (_main_list[i]._crossing == false)
{
Console.WriteLine(_main_list[i]._id);
}
}
Console.ReadKey();
}
}
}
Если кратко то считываем прямоугольники ,пробегаемся по всем без повторений,если пересекаются то считаем площадь пересечения и прибавляем к _answer_count и у обоих прямоугольников _crossing присваиваем true, если не пересекаются - идем дальше.Все просто.
При небольших данных все нормально работает и площадь корректно считается.
Но когда беру много прямоугольников то площадь высчитывается неверно.
Например , https://drive.google.com/file/d/1HS5mzRcbyylOIfThSCNYwisl2zHFLGiL/view
При использовании тестовых данных ответом будет: 104241 для первой части, #806 для второй, а у меня в первой части задания выводится 171109 (хотя вторая часть задания выводит верно 806)

Не понимаю где ошибка, может быть кто-нибудь догадается и подскажет мне? очень уж интересно
UPDATE 1 Код с использованием сканирующей прямой
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp5
{
class Program
{
class Segment : IComparable<Segment>
{
public int xl, xr, y, type, id;
public bool crossing;
public Segment(int xl, int xr, int y, int type, int id)
{
this.xl = xl;
this.xr = xr;
this.y = y;
this.type = type;
this.id = id;
crossing = false;
}
public int CompareTo(Segment obj)
{
if (this.y > obj.y)
return 1;
if (this.y < obj.y)
return -1;
else
return 0;
}
}
static void Main(string[] args)
{
List<int> x = new List<int>();
List<Segment> seg = new List<Segment>();
string _input_line = " ";
int n = 0;
int _sum_pryamo = 0;
while (!string.IsNullOrEmpty(_input_line))
{
_input_line = Console.ReadLine();
if (string.IsNullOrEmpty(_input_line))
break;
string[] splitted = _input_line.Split('#', '@', ',', ':', 'x');
int id = Convert.ToInt32(splitted[1]);
int x1 = Convert.ToInt32(splitted[2].Trim());//+
int y1 = Convert.ToInt32(splitted[3]) + Convert.ToInt32(splitted[5]);
int x2 = Convert.ToInt32(splitted[4].Trim()) + x1;
int y2 = Convert.ToInt32(splitted[3]);
_sum_pryamo += Convert.ToInt32(splitted[4].Trim()) * Convert.ToInt32(splitted[5]);
x.Add(x1);
x.Add(x2);
Segment item_low = new Segment(x1, x2, y1, 1, id);
Segment item_high = new Segment(x1, x2, y2, -1, id);
seg.Add(item_low);
seg.Add(item_high);
n++;
}
x.Sort();
seg.Sort();
int answer = 0;
for (int i = 1; i < 2 * n; ++i)
{
int prevY = 0, cnt = 0;
for (int j = 0; j < 2 * n; ++j)
{
if (seg[j].xr <= x[i - 1] || seg[j].xl >= x[i])
{
continue;
}
if (cnt == 0)
{
prevY = seg[j].y;
}
cnt += seg[j].type;
if (cnt == 0)
{
answer += (seg[j].y - prevY) * (x[i] - x[i - 1]);
}
}
}
Console.WriteLine(_sum_pryamo - answer);
Console.ReadKey();
}
}
}
Ответы (1 шт):
Эту задачу можно решить с использованием метода сканирующей прямой (sweep line algorithm) непрямым образом.
Нетрудно найти реализацию получения площади объединения прямоугольников (три случайные ссылки).
Edit: Следующее неверно, тоже не учитывает множественные пересечения:
Если из общей площади всех прямоугольников вычесть площадь объединения - получим площадь пересечения.
