choosing a next point in boundary - c#

I'm trying to apply bound hall algorithm on set of points which are deployed randomly.
I based on the angle between the previous point and the neighborhood points of the current point to choose the next point with minimal angel.
What i'm asking for is in some cases the boundary stop generating any point and I've actually debugged the code many times and couldn't figure out what the problem.
The pic of case and the code are given below.
ArrayList angles = new ArrayList();
for (int s = 0; s < node.SensorNeighbors.Count; s++)
{
Node n = node.SensorNeighbors[s];
if (backboneNodes.Count != 1) // backboneNode is array hase nodes in boundary
{
Node previous = backboneNodes[backboneNodes.Count - 2];
Double Angle = Math.Atan2(previous.y - node.y, previous.x - node.x) - Math.Atan2(n.y - node.y, n.x - node.x);
angles.Add(Angle);
}
if (backboneNodes.Count == 1)
{
Double Angle = Math.Atan2(520 - node.y, node.x - node.x) - Math.Atan2(n.y - node.y, n.x - node.x);
angles.Add(Angle);
}
}
int index = 0;
double minAngle = int.MaxValue;
for (int s = 0; s < angles.Count; s++)
{
if ((double)angles[s] < minAngle)
{
minAngle = (double)angles[s];
index = angles.IndexOf(minAngle);
}
}
Node Nnode = node.SensorNeighbors[index];
int iRadius = (int)Math.Sqrt(Math.Pow(node.x - Nnode.x, 2) + Math.Pow(node.y - Nnode.y, 2));
node.aConnections.Add(node, Nnode, (int)(fTransmissionCost * iRadius / iTransmissionRadius), iReceiveCost, iTransmitterDelay);
node = Nnode;

Related

Is my method for Recursive division for my maze generator correct?

Im trying to make a maze generator using Recursive division explained here: https://en.wikipedia.org/wiki/Maze_generation_algorithm
The first iteration works for me. But when I do it multiple times It doesnt do it properly.
Question is: Is my recursve method corrext? The if and else statements followed up with either a return or recusion.
private void DevideRecursive(int pMinX, int pMaxX, int pMinY, int pMaxY)
{
Debug.Log("minx: " + pMinX);
Debug.Log("maxx: " + pMaxX);
Debug.Log("miny: " + pMinY);
Debug.Log("maxy: " + pMaxY);
int randomX = Random.Range(pMinX +1, pMaxX);
int randomY = Random.Range(pMinY +1, pMaxY);
int randomWall = Random.Range(0, 4);
List<GameObject> WalllistX1 = new List<GameObject>();
List<GameObject> WalllistX2 = new List<GameObject>();
List<GameObject> WalllistY1 = new List<GameObject>();
List<GameObject> WalllistY2 = new List<GameObject>();
List<List<GameObject>> MainWallList = new List<List<GameObject>>();
MainWallList.Add(WalllistX1);
MainWallList.Add(WalllistX2);
MainWallList.Add(WalllistY1);
MainWallList.Add(WalllistY2);
//// add a wall on a random x coordinate
for (int x = pMinX; x < pMaxX; x++)
{
GameObject wall = Instantiate(WallHor);
wall.transform.position = new Vector2(tilesize * x + tilesize / 2, tilesize * randomY);
if (x < randomX)
{
WalllistX1.Add(wall);
}
else
{
WalllistX2.Add(wall);
}
}
//// add a wall on a random y coordinate
for (int y = pMinY; y < pMaxY ; y++)
{
GameObject wall = Instantiate(WallVer);
wall.transform.position = new Vector2(tilesize * randomX, tilesize * y + tilesize / 2);
if (y < randomY)
{
WalllistY1.Add(wall);
}
else
{
WalllistY2.Add(wall);
}
}
//make a hole in 3 out of tht 4 walls randomly
for (int i = 0; i < MainWallList.Count; i++)
{
Debug.Log("list" + MainWallList.Count);
if (randomWall != i)
{
Debug.Log("1: " + WalllistX1.Count);
Debug.Log("2: " + WalllistX2.Count);
Debug.Log("3: " + WalllistY1.Count);
Debug.Log("4: " + WalllistY2.Count);
RemoveWall(MainWallList[i]);
}
}
////
////
//// If either of the walls have a cell with only 1 grid stop the recursion
if (randomX - pMinX <= 1 || pMaxY - randomY <= 1)
{
return;
}
else
{
DevideRecursive(pMinX, randomY, randomX, pMaxY);
}
if (pMaxX - randomX <= 1 || pMaxY - randomY <= 1)
{
return;
}
else
{
DevideRecursive(randomY, pMaxX, randomX, pMaxY);
}
if (randomX - pMinX <= 1 || randomY - pMinY <=1)
{
return;
}
else
{
DevideRecursive(pMinX, randomY, pMinY, randomX);
}
if (pMaxX - randomX <= 1 || randomY - pMinY <= 1)
{
return;
}
else
{
DevideRecursive(randomY, pMaxX, pMinY, randomX);
}
}
what my code does(or is supposed to do). in a rectangular maze, build at random points two walls that are perpendicular to each other. These two walls divide the large chamber into four smaller chambers separated by four walls. Choose three of the four walls at random, and open a one cell-wide hole at a random point in each of the three. Continue in this manner recursively, until every chamber has a width of one cell in either of the two directions.
here is quick illustration of the frist iteration https://gyazo.com/08e1cb2483fcf841e4d854d001c51647
for example the next iteration is going to be in the upper left room. then minX stays the same. MaxX becomes the RandomX. the same for the Y values. then it should do the same again(creating 2 walls )

Randomly generate blocks on a flat map

I'm trying to randomly generate blocks on a flat map and make it so that they don't overlap each other.
I have made a matrix (c# array) of the size of the map (500x500), the blocks have a scale between 1 and 5.
The code works but if a generated block overlaps another one, it is destroyed and not regenerated somewhere else.
Only around 80 of the 1000 blocks I try to generate don't overlap another block.
Here is a picture of the map with around 80 blocks generated, the green squares are blocks
void generateElement(int ratio, int minScale, int maxScale, GameObject g) {
bool elementFound = false;
for (int i = 0; i < ratio * generationDefault; i++) {
GameObject el;
// Randomly generate block size and position
int size = Random.Range(minScale, maxScale + 1);
int x = Random.Range(0, mapSizex + 1 - size);
int y = Random.Range(0, mapSizey + 1 - size);
// Check if there is already an element
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] != null)
elementFound = true;
if (elementFound)
continue;
else {
el = (GameObject)Instantiate(g, new Vector3(x + (float)size / 2, (float)size / 2, y + (float)size / 2), Quaternion.Euler(0, 0, 0));
el.transform.localScale *= size;
}
// Create element on map array
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] == null) {
map[j][k] = el.GetComponent<ObjectInterface>();
}
}
}
I thought of 3 possible fixes
I should set the size of the block depending of the place it has.
I should use another randomization algorithm.
I'm not doing this right.
What do you think is the best idea ?
UPDATE
I got the code working much better. I now try to instantiate the blocks multiple times if needed (maximum 5 for the moment) and I fixed the bugs. If there are already many elements on the map, they will not always be instantiated and that's what I wanted, I just have to find the right amount of times it will try to instantiate the block.
I tried instantiating 1280 elements on a 500x500 map. It takes only about 1.5 second and it instantiated 1278/1280 blocks (99.843%).
void generateElement(int ratio, int minScale, int maxScale, GameObject g) {
bool elementFound = false;
int cnt = 0;
// Generate every block
for (int i = 0; i < ratio * generationDefault; i++) {
GameObject el = null;
// Randomly generate block size and position
int size, x, y, tryCnt = 0;
// Try maximum 5 times to generate the block
do {
elementFound = false;
// Randomly set block size and position
size = Random.Range(minScale, maxScale + 1);
x = Random.Range(0, mapSizex + 1 - size);
y = Random.Range(0, mapSizey + 1 - size);
// Check if there is already an element
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] != null)
elementFound = true;
tryCnt++;
} while (elementFound && tryCnt < 5);
if (tryCnt >= 5 && elementFound) continue;
// Instantiate the block
el = (GameObject)Instantiate(g, new Vector3(x + (float)size / 2, (float)size / 2, y + (float)size / 2), Quaternion.Euler(0, 0, 0));
el.transform.localScale *= size;
// Create element on map array
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] == null) {
map[j][k] = el.GetComponent<ObjectInterface>();
}
cnt++;
}
print("Instantiated " + cnt + "/" + ratio * generationDefault);
}
This is incredibly difficult to do well.
Here's a quick solution you'll maybe like ... depending on your scene.
actualWidth = 500 //or whatever. assume here is square
// your blocks are up to 5 size
chunkWidth = actualWidth / 5
// it goes without saying, everything here is an int
kChunks = chunkWidth*chunkWidth
List<int> shuf = Enumerable.Range(1,kChunks).OrderBy(r=>Random.value).ToList();
howManyWanted = 1000
shuf = shuf.Take(howManyWanted)
foreach( i in shuf )
x = i % actualWidth
y = i / actualWidth
make block at x y
put block in list allBlocks
HOWEVER ............
...... you'll see that this looks kind of "regular", so do this:
Just randomly perturb all the blocks. Remember, video game programming is about clever tricks!
Ideally, you have to start from the middle and work your way out; in any event you can't just do them in a line. Shuffling is OK. So, do this ..
harmonic = 3 //for example. TRY DIFFERENT VALUES
function rh = Random.Range(1,harmonic) (that's 1 not 0)
function rhPosNeg
n = rh
n = either +n or -n
return n
function onePerturbation
{
allBlocks = allBlocks.OrderBy(r => Random.value) //essential
foreach b in allBlocks
newPotentialPosition = Vector2(rhPosNeg,rhPosNeg)
possible = your function to check if it is possible
to have a block at newPotentialPosition,
however be careful not to check "yourself"
if possible, move block to newPotentialPosition
}
The simplest approach is just run onePerturbation, say, three times. Have a look at it between each run. Also try different values of the harmonic tuning factor.
There are many ways to perturb fields of differently-sized blocks, above is a KISS solution that hopefully looks good for your situation.
Coding note...
How to get sets of unique random numbers.
Just to explain this line of code...
List<int> shuf = Enumerable.Range(1,kChunks).OrderBy(r=>Random.value).ToList();
If you are new to coding: say you want to do this: "get a hundred random numbers, from 1 to million, but with no repeats".
Fortunately, this is a very well known problem with a very simple solution.
The way you get numbers with no repeats, is simply shuffle all the numbers, and then take how many you want off the top.
For example, say you need a random couple of numbers from 1-10 but with no repeats.
So, here's the numbers 1-10 shuffled: 3,8,6,1,2,7,10,9,4,5
Simply take what you need off the front: so, 3, 8, 6 etc.
So to make an example let's say you want twelve numbers, no repeats, from 1 through 75. So the first problem is, you want a List with all the numbers up to 75, but shuffled. In fact you do that like this ..
List<int> shuf = Enumerable.Range(1,75).OrderBy(r=>Random.value).ToList();
So that list is 75 items long. You can check it by saying foreach(int r in shuf) Debug.Log(r);. Next in the example you only want 12 of those numbers. Fortunately there's a List call that does this:
shuf = shuf.Take(12)
So, that's it - you now have 12 numbers, no repeats, all random between 1 and 75. Again you can check with foreach(int r in shuf) Debug.Log(r);
In short, when you want "n" numbers, no repeats, between 1 and Max, all you have to so is this:
List<int> shuf = Enumerable.Range(1,Max).OrderBy(r=>Random.value).ToList();
shuf = shuf.Take(n);
et voilĂ , you can check the result with foreach(int r in shuf) Debug.Log(r);
I just explain this at length because the question is often asked "how to get random numbers that are unique". This is an "age-old" programming trick and the answer is simply that you shuffle an array of all the integers involved.
Interestingly, if you google this question ("how to get random numbers that are unique") it's one of those rare occasions where google is not much help, because: whenever this question is asked, you get a plethora of keen new programmers (who have not heard the simple trick to do it properly!!) writing out huge long complicated ideas, leading to further confusion and complication.
So that's how you make random numbers with no repeats, fortunately it is trivial.
if (elementFound) continue; will skip out this current loop iteration. You need to wrap the int x=Random..; int y=Random()..; part in a while loop with the condition being while(/* position x/y already occupued*/) { /* generate new valid point */} like this for example:
void generateElement(int ratio, int minScale, int maxScale, GameObject g) {
for (int i = 0; i < ratio * generationDefault; i++) {
GameObject el;
// Randomly generate block size and position
bool elementFound = false;
int size, x, y;
do
{
elementFound = false;
size = Random.Range(minScale, maxScale + 1);
x = Random.Range(0, mapSizex + 1 - size);
y = Random.Range(0, mapSizey + 1 - size);
// Check if there is already an element
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] != null)
elementFound = true;
} while(elementFound);
el = (GameObject)Instantiate(g, new Vector3(x + (float)size / 2, (float)size / 2, y + (float)size / 2), Quaternion.Euler(0, 0, 0));
el.transform.localScale *= size;
// Create element on map array
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] == null) {
map[j][k] = el.GetComponent<ObjectInterface>();
}
}
}
You shouldn't be getting that many collisions.
Assuming your blocks were ALL 5 units wide and you're trying to fit them into a grid of 500,500 you would have 100*100 spaces for them at minimum, which gives 10,000 spaces into which to fit 1,000 blocks.
Try playing around with this code:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
var result = PlaceNonOverlappingBlocks(1000, 5, 500, 500);
}
static List<Block> PlaceNonOverlappingBlocks(int count, int maxBlockSize, int mapX, int mapY)
{
var map = new bool[mapY, mapX];
var rng = new Random();
var result = new List<Block>(count);
int collisions = 0;
while (count > 0)
{
int size = rng.Next(1, maxBlockSize + 1);
int x = rng.Next(0, mapX - size);
int y = rng.Next(0, mapY - size);
if (fits(map, x, y, size))
{
result.Add(new Block(x, y, size));
addToMap(map, x, y, size);
--count;
}
else
{
if (++collisions> 100000)
throw new InvalidOperationException("Hell has frozen over");
}
}
// This is just for diagnostics, and can be removed.
Console.WriteLine($"There were {collisions} collisions.");
return result;
}
static void addToMap(bool[,] map, int px, int py, int size)
{
for (int x = px; x < px+size; ++x)
for (int y = py; y < py + size; ++y)
map[y, x] = true;
}
static bool fits(bool[,] map, int px, int py, int size)
{
for (int x = px; x < px + size; ++x)
for (int y = py; y < py + size; ++y)
if (map[y, x])
return false;
return true;
}
internal class Block
{
public int X { get; }
public int Y { get; }
public int Size { get; }
public Block(int x, int y, int size)
{
X = x;
Y = y;
Size = size;
}
}
}
}

While loop wrong output given

I have a list of Points List<Point> newcoor = new List<Point>(); and specific coordinate which is the center of the List of Points. int centerx, centery;
What I want to do is add 1 with centerx and subtract 1 with centery until it reaches a combination that will match a Point inside a list. Then store that point inside an array. This is my code:
List<Point> newcoor = new List<Point>(); // list of points that where the tempx and tempy will be compared to.
//...
Point[] vector = new Point[4];
int x = 0;
while (x <= 3)
{
var tempx = centerx + 1; //add 1 to centerx
var tempy = centerx - 1; //subtrat 1 to centery
int y = 0;
if (y < newcoor.Count() - 1 && newcoor[y].X == tempx && newcoor[y].Y == tempy) // compare if there is a Point in the List that is equal with the (tempx,tempy) coordinate
{
vector[x].X = tempx;// store the coordinates
vector[x].Y = tempy;
}
break; // this is what I don't understand, I want to exit the loop immediately if the if-condition is true. And add 1 to x so the while loop will update.
}
Tried New Code:
for (int y = 0; y < newcoor.Count() - 1; y++)
{
var tempx = centerx + 1;
var tempy = centery - 1;
for (int x = 0; x < newcoor.Count() - 1; x++)
{
if (newcoor[y].X == tempx && newcoor[y].Y == tempy)
{
//vectorPoints.Add(new Point(tempx,tempy));
MessageBox.Show("success");
}
}
}
But no messagebox success shows, meaning there was no match. but there must be.
All I need is 4 output that's why I have conditon while (x <= 3)
Update:
My centerx = 30 and centery = 28
And here is my list:
What I want to do is add 1 to centerx and subtract 1 to centery
from original centerx= 30 and centery= 28, it should be
(31,27)
(32,26)
(33,25)
(34,24)
(35,23) <----- This should be the to the one with the same value inside my list, which is shown in the image above.
No idea what you're hoping for here, but there's several problems I can spot anyway;
Firtly, tempx and tempy will be the same value on each loop, as nothing inside the loop manipulates centerx or centery.
Secondly, the loop will exit on the first run, as the break statement is not inside the if {..} block. Perhaps you meant;
if (y < newcoor.Count() - 1 && newcoor[y].X == tempx && newcoor[y].Y == tempy)
{
vector[x].X = tempx;// store the coordinates
vector[x].Y = tempy;
break; // <-- needs to be inside the if{..} block
}

How to group near coordinates

I'm having my thesis "Multiple Choice Examination Checker" and I'm having a big issue about what to do with my problem. I got a picture image (a bitmap specifically) here it is, so you can see:
This is the image with the detectedbox, I will describe this:
This is an examination paper, 1-50 items. each number has a corresponding box(right side of the number, that serves as a container for the answer)
This pictures is just a sample, the number of detected boxes may vary. My approximation is it contains 150-200 detected boxes.
Each detectedboxes are stored in a List(MCvBOX2D) which holds the detectedboxes' size, center, etc.
I transferred those center coordinates in a new list List(PointF) center;
Each box from the image, may have 3-5 detectedboxes. as you can see there are more than one detectedboxes in each of the boxes from the image.
I sorted all the detectedboxes in ascending order, so I would know which will possibly be the number1, number2, and so on..
Here is some of my code, which contains the sorting of boxes.
List<PointF> center = new List<PointF>();
List<PointF> centernew = new List<PointF>();
foreach (MCvBox2D box in lstRectangles)
{
// this code transfers every center-coordinates of detected boxes
// to a new list which is center
center.Add(new PointF(box.center.X, box.center.Y));
}
// and this one sorts the coordinates in ascending order.
centernew = center.OrderBy(p => p.Y).ThenBy(p => p.X).ToList();
I'm done with the sorting part, now my problem is, since there many detected boxes in every box from the image, I would like to group the sortedlist of center-coordinates, so I could eliminate the other detectedboxes and get only one detectedbox for each number.
I know it's hard to understand so I'll explain more.
Let's say my sortedlist of detectedboxes contains first five center-coordinates which are:
let's say this are the center-coordinates of each of the detectedboxes from first box of the image.
center[0] = [ 45.39, 47.6]
center[1] = [ 65.39, 47.6]
center[2] = [ 45.40, 47.10]
center[3] = [ 65.45, 47.25]
center[4] = [ 46.01, 47.50]
and the 2nd are:
center[5] = [ 200.39, 47.2]
center[6] = [ 45.39, 47.2]
center[7] = [ 45.39, 47.3]
center[8] = [ 45.39, 47.55]
My goal is to organize all the sorted detectedboxes inside the list, I must be able to group all the center-coordinates that have close value with the other center, specifically their Y-coordinates.
var rand = new Random();
var threshold = 1;
var points = new List<PointF>();
for (int i = 0; i < 20; i++)
{
points.Add(new PointF((float) rand.NextDouble()*10, (float) rand.NextDouble()*10));
}
Console.WriteLine(points.Count);
for (int i = 0; i < points.Count(); i++)
{
for (int j = i + 1; j < points.Count(); )
{
var pointHere = points[i];
var pointThere = points[j];
var vectorX = pointThere.X - pointHere.X;
var vectorY = pointThere.Y - pointHere.Y;
var length = Math.Sqrt(Math.Pow(vectorX, 2) + Math.Pow(vectorY, 2));
if (length <= threshold)
{
points.RemoveAt(j);
}
else
{
j += 1;
}
}
}
Console.WriteLine(points.Count);
You can calculate the distance between a given point and any other point in the list. If the distance is less than half the width of a box, you can be pretty sure that it's part of the same box.
double threshold = 3.0; // Make this whatever is appropriate
for (int i = center.Count - 1; i >= 0; --i)
if (center.Any(p => p != center[i] && Distance(center[i], p) < threshold))
center.Remove(center[i]);
And you could use this for your Distance() method:
private double Distance(PointF p1, PointF p2)
{
double deltaX = Math.Abs(p1.X - p2.X);
double deltaY = Math.Abs(p1.Y - p2.Y);
return Math.Sqrt((deltaX * deltaX) + (deltaY * deltaY));
}
You could use Distinct with an custom IEqualityComparer (see MSDN).
As an example, define a class:
class BoxEqualityComparer : IEqualityComparer<MCvBox2D>
{
private static Double Tolerance = 0.01; //set your tolerance here
public Boolean Equals(MCvBox2D b1, MCvBox2D b2)
{
if (CentersAreCloseEnough(b1.Center, b2.Center))
{
return true;
}
else
{
return false;
}
}
private Boolean CentersAreCloseEnough(PointF c1, PointF c2)
{
return Math.Abs(c1.X - c2.X) < Tolerance && Math.Abs(c1.Y - c2.Y) < Tolerance;
}
}
then use the method in your code like so:
var distinctRectangles = lstRectangles.Distinct(new BoxEqualityComparer());
You are free to implement CentersAreCloseEnough(PointF c1, PointF c2) however you would like; you could use vector distance, absolute distance in x and y, etc.
If you are just concerned about positions with Y coordinates, just sort by that number. If you want to sort both you can add both X and Y and use that number to sort them. Here is an example of what I meen.
for(int i = 0; i < points.length - 1; i++)
{
int temp = points[i].x + points[i].y;
for(int j = i+1; j < points.length; i++)
{
int temp2 = point[j].x + points[j].y;
if(temp2 < temp)
{
Point jugglePoint = points[i];
points[i] = points[j];
points[j] = jugglePoint;
}
}
}

Simple Cluster algorithm 2D. Detecting clumps of points

Anyone know a simple algorithm to implement in C# to detect monster groups in a 2D game.
EX:
100 Range around the char there are monsters. I want to detect which monsters are within range 2 of each other, and if there is at-least 5 together, use the Area of Effect skill on that location. Otherwise use the single-target skill.
A link to an implementation would be great, C# preferably. I just get lost reading the Wikipedia articles.
EDIT:
"your question is incomplete. what do you want to do exactly? do you want to find all groups? the biggest group? any group, if there are groups, none otherwise? please be more specific." -gilad hoch
I want to find all groups within 100 units of range around the main character. The groups should be formed if there are at-least 5 or more monsters all within 2 range of each other, or maybe within 10 range from the center monster.
So the result should be probably a new List of groups or a List of potential target locations.
a very simple clustering algorithm is the k-mean algorithm. it is like
create random points
assign all points to the nearest point, and create groups
relocate the original points to the middle of the groups
do the last two steps several times.
an implementation you can find for example here, or just google for "kmean c#"
http://kunuk.wordpress.com/2011/09/20/markerclusterer-with-c-example-and-html-canvas-part-3/
I recently implemented the algorithm given in this paper by Efraty, which solves the problem by considering the intersections of circles of radius 2 centered at each given point. In simple terms, if you order the points in which two circles intersect in clockwise order, then you can do something similar to a line sweep to figure out the point in which a bomb (or AoE spell) needs to be launched to hit the most enemies. The implementation is this:
#include <stdio.h>
#include <cmath>
#include <algorithm>
using namespace std;
#define INF 1e16
#define eps 1e-8
#define MAXN 210
#define RADIUS 2
struct point {
double x,y;
point() {}
point(double xx, double yy) : x(xx), y(yy) {}
point operator*(double ot) {
return point(x*ot, y*ot);
}
point operator+(point ot) {
return point(x+ot.x, y+ot.y);
}
point operator-(point ot) {
return point(x-ot.x, y-ot.y);
}
point operator/(double ot) {
return point(x/ot, y/ot);
}
};
struct inter {
double x,y;
bool entry;
double comp;
bool operator< (inter ot) const {
return comp < ot.comp;
}
};
double dist(point a, point b) {
double dx = a.x-b.x;
double dy = a.y-b.y;
return sqrt(dx*dx+dy*dy);
}
int N,K;
point p[MAXN];
inter it[2*MAXN];
struct distst {
int id, dst;
bool operator<(distst ot) const {return dst<ot.dst;}
};
distst dst[200][200];
point best_point;
double calc_depth(double r, int i) {
int left_inter = 0;
point left = p[i];
left.y -= r;
best_point = left;
int tam = 0;
for (int k = 0; k < N; k++) {
int j = dst[i][k].id;
if (i==j) continue;
double d = dist(p[i], p[j]);
if (d > 2*r + eps) break;
if (fabs(d)<eps) {
left_inter++;
continue;
}
bool is_left = dist(p[j], left) < r+eps;
if (is_left) {
left_inter++;
}
double a = (d*d) / (2*d);
point diff = p[j] - p[i];
point p2 = p[i] + (diff * a) / d;
double h = sqrt(r*r - a*a);
it[tam].x = p2.x + h*( p[j].y - p[i].y ) / d;
it[tam].y = p2.y - h*( p[j].x - p[i].x ) / d;
it[tam+1].x = p2.x - h*( p[j].y - p[i].y ) / d;
it[tam+1].y = p2.y + h*( p[j].x - p[i].x ) / d;
it[tam].x -= p[i].x;
it[tam].y -= p[i].y;
it[tam+1].x -= p[i].x;
it[tam+1].y -= p[i].y;
it[tam].comp = atan2(it[tam].x, it[tam].y);
it[tam+1].comp = atan2(it[tam+1].x, it[tam+1].y);
if (it[tam] < it[tam+1]) {
it[tam].entry = true;
it[tam+1].entry = false;
}
else {
it[tam].entry = false;
it[tam+1].entry = true;
}
if (is_left) {
swap(it[tam].entry, it[tam+1].entry);
}
tam+=2;
}
int curr,best;
curr = best = left_inter;
sort(it,it+tam);
for (int j = 0; j < tam; j++) {
if (it[j].entry) curr++;
else curr--;
if (curr > best) {
best = curr;
best_point = point(it[j].x, it[j].y);
}
}
return best;
}
int main() {
scanf("%d", &N);
for (int i = 0; i < N; i++) {
scanf("%lf %lf", &p[i].x, &p[i].y);
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
dst[i][j].id = j;
dst[i][j].dst = dist(p[i],p[j]);
}
sort(dst[i],dst[i]+N);
}
int best = 0;
point target = p[0];
for (int i = 0; i < N; i++) {
int depth = calc_depth(RADIUS, i);
if (depth > best) {
best = depth;
target = best_point;
}
}
printf("A bomb at (%lf, %lf) will hit %d target(s).\n", target.x, target.y, best+1);
}
Sample usage:
2 (number of points)
0 0
3 0
A bomb at (1.500000, 1.322876) will hit 2 targets.

Categories

Resources