巨人与鬼:
题目:
一组n个巨人正与n个鬼进行战斗,每个巨人的武器是一个质子炮, 它可以把一串质子流射中鬼而把鬼消灭。质子流沿直线行进,在击中鬼时就终止。巨人决定采取下述策略。他们寻找鬼配对,以形成n个巨人─鬼对,。然后每个巨人同时向他选取的鬼射出一串质子流。我们知道,让质子流互相交叉是很危险的。因此巨人选择的配对方式应该使质子流都不会交叉。假定每个巨人和每个鬼的位置都是平面上的一个固定点,并且没有三个位置共线, 求一种配对方案。
下面的输入是笔者自己设计的:
输入:
有多组输入,第一行为n,第二行为n个巨人的坐标(浮点型),第三行为n个巨人的坐标(浮点型)
输出:
巨人编号(这里的编号就是各坐标输入的次序0——2*n-1)--鬼的编号。
样例输入:
20 0 1 2
2 1 -1 4
样例输出(有可能有多种匹配方案,只要符合要求即可):
0--2
1--3
这一题书上说是分治+递归,但是笔者刚开始只是当成数理题做,并没有意识到其分治的思想,下面的代码也是按照笔者最开始的数理方法写的,分治思想的代码之后再补上。
1 .首先,要如何想到这种极坐标的结构呢?事实上,可以这么想:对于一个巨人A,比如下图远点位置的蓝圆圈,总要有一个鬼和它配对(题中说n个鬼,n个巨人),因此,现在我们要在n个鬼当中选1个鬼给巨人A怼,这样就很自然地想到以该巨人A为原点,鬼们绕着这个巨人,这样再来考虑如何选鬼被巨人A怼会直观一些,考虑到题目中说,巨人选择的配对方式应该使质子流都不会交叉,因此我们还要考虑其它巨人的空间位置。
2. 如果选图中鬼1,接下去巨人B——鬼2,巨人C——鬼3,看似没什么毛病,但是要注意,如果我们选巨人A——鬼1,那么巨人B——鬼2很可能与质子流巨人A——鬼1相撞,那么怎么办呢,有没有一种优美的方法能天然地避开这种撞击问题呢?诶,还真有:从下图中的x轴正向出发,沿着逆时针方向找到第一个安全鬼(解释一下安全鬼:在下图中就是鬼2,因为鬼1前面还有一个巨人B,为了避免B的质子流与A的质子流相撞,安全起见,我们把鬼1让给B,找下一个鬼怼,所以如果鬼1和鬼2之间还有一个巨人E,那么鬼2也得让给巨人B、E,找下一个安全鬼。)
3.有些细心的同学就会问:我们该从哪个巨人开始匹配,好,给大家一点时间捋一捋,想一想:
好,我们该从哪个巨人开始匹配呢?答案是:从最底下的那个巨人开始匹配,为什么呢?请看下图:
如果我们不从位于最下面的巨人B开始匹配,而从上面一点A的开始匹配,采用刚才上面讨论的方法,得到:巨人A——鬼1,好,这样就会有问题了,巨人B潜伏在下面,很可能就会一箭射穿巨人A——鬼1质子流,但是如果我们每次都从最下面的巨人开始匹配的话,就排除了有潜在巨人在x轴下面的隐患,当然鬼是可以在x轴下面的。
4. 好,基本策略我们已经弄清了,现在代码要怎么写呢?不,应该问伪代码要怎么写呢?来,借一步说话——>
1.找到当前最下面的巨人A,且该巨人A没被访问过
2.以该巨人A为原点,以逆时针方向(这里涉及到按角度排序)找到第一个未被访问的安全鬼,匹配之
3.标记该巨人A和匹配的鬼被访问过。
4.如果还有巨人未匹配,转1.
5. OK,基本伪代码已经有了,直接上代码吧,建议大家自己先写。
#include<iostream>
#include<math.h>
#include<algorithm>
using namespace std;
#define Maxsize 1005
#define INF 10000000
/*
INPUT EXAMPLE:
2
0 0 1 2
2 1 -1 4
3
0 0 2 2 1 3
3 0 -1 4 -2 1
*/
struct Monster
{
int ind;
float x;
float y;
int cat;//category: giant(1) or gost(0).
}A[Maxsize], Angle[Maxsize];
int visit[Maxsize];
bool cmp(Monster a, Monster b)
{
float x1 = a.x;
float y1 = a.y;
float x2 = b.x;
float y2 = b.y;
if (x1*x2< 0)//
{
return x1 > 0 ? 1 : 0;//negtive one ranks later
}
else
{
if (x1 < 0)//x1 and x2 are both negative.
{
x1 = -x1;
x2 = -x2;
return x2*y1 > y2*x1;//for negative:sorted by abs(y/x),larger one ranks front.
}
else
return x2*y1 < y2*x1;
}
}
void SortByAngle(int centerind,int n)
{
int i,k=0;
float centerx, centery;
for (i = 0;i < n;i++)
if (visit[A[i].ind]==0&&A[i].ind == centerind)
{
centerx = A[i].x;
centery = A[i].y;
break;
}
for (i = 0;i < n;i++)
{
if (visit[A[i].ind] == 0&&A[i].ind != centerind)
{
//In fact Angle plays a role of temp array.
Angle[k].ind = A[i].ind;
Angle[k].cat = A[i].cat;
Angle[k].x= A[i].x-centerx;
Angle[k++].y = A[i].y - centery;
}
}
sort(Angle, Angle + k, cmp);
}
int main()
{
//Input
int n,i;//n:the number of stg(or gnt).
while (cin >> n)
{
//Initialize the visit
memset(visit, 0, sizeof(visit));
//Input giants' position
for (i = 0;i < n;i++)
{
cin >> A[i].x >> A[i].y;
A[i].ind = i;
A[i].cat = 1;
}
//Input ghosts' position
for (i = n;i < 2*n;i++)
{
cin >> A[i].x >> A[i].y;
A[i].ind = i;
A[i].cat = 0;
}
/* check whether the input is correct.
for (i = 0;i < 2 * n;i++)
cout << A[i].ind << " " << A[i].x << " " << A[i].y << endl;
*/
int s = 2*n;
int fstmgst = 0;
while(s)
{
//select the centerind;
float miny = INF;
int centerind;
for (i = 0;i < 2*n;i++)
if(visit[A[i].ind]==0)
{
if (A[i].cat==1&&miny > A[i].y)
{
miny = A[i].y;
centerind = A[i].ind;
}
}
//sort A and then asign to angle.
SortByAngle(centerind, 2 * n);
for (i = 0;i < s;i++)
if(visit[Angle[i].ind]==0)
{
if (Angle[i].cat == 0 && fstmgst == 0)
{
//match centerind and Angle[i].ind
cout << centerind << "--" << Angle[i].ind<<endl;
visit[centerind] = 1;
visit[Angle[i].ind] = 1;
break;
}
else
{
if(Angle[i].cat==1)
fstmgst++;
else
{
fstmgst--;
}
}
}//for
s -= 2;
}
}
system("pause");
return 0;
}
如有错误,希望各位踊跃指出。