T3:
经过 11 年的韬光养晦,某国研发出了一种新的导弹拦截系统,凡是与它的距离不超过其工作半径的导弹都能够被它成功拦截。当工作半径为 0 时,则能够拦截与它位置恰好相同的导弹。但该导弹拦截系统也存在这样的缺陷:每套系统每天只能设定一次工作半径。而当天的使用代价,就是所有系统工作半径的平方和。某天,雷达捕捉到敌国的导弹来袭。由于该系统尚处于试验阶段,所以只有两套系统投入工作。如果现在的要求是拦截所有的导弹,请计算这一天的最小使用代价.
输入
第一行包含 4 个整数x1、y1、x2、y2,每两个整数之间用一个空格隔开,表示这两套导弹拦截系统的坐标分别为(x1, y1)、(x2, y2)。
第二行包含 1 个整数 N,表示有 N颗导弹。接下来 N行,每行两个整数 x、y,中间用一个空格隔开,表示一颗导弹的坐标(x, y)。不同导弹的坐标可能相同。
输出
输出只有一行,包含一个整数,即当天的最小使用代价。
【提示】
两个点(x1, y1)、(x2, y2)之间距离的平方是(x1− x2)^2+(y1−y2)^2.两套系统工作半径 r1、r2的平方和,是指 r1、r2 分别取平方后再求和,即 r1^2+r2^2.
样例输入
0 0 10 0
2
-3 3
10 0
样例输出
18
数据范围限制
提示
【样例 1 说明】
样例 1 中要拦截所有导弹,在满足最小使用代价的前提下,两套系统工作半径的平方分别为 18 和 0。
【输入输出样例 2】
输入:
0 0 6 0
5
-4 -2
-2 3
4 0
6 -2
9 1
输出:
30
【样例 2 说明】
样例中的导弹拦截系统和导弹所在的位置如下图所示。要拦截所有导弹,在满足最小使用代价的前提下,两套系统工作半径的平方分别为 20 和 10。
这道题是贪心,即一个搜索范围扩大,另一个搜索范围减少,一个捕前i个的最大值,一个捕后i个的最大值,两数结合得出的最小值即为最终的answer。
var a,c:array[1..100000]of longint; i,n,x,y,x1,x2,y1,y2,tot,ans:longint; function max(x,y:LOngint):LOngint; begin if x>y then exit(x) else exit(y); end; function min(x,y:LOngint):LOngint; begin if x>y then exit(y) else exit(x); end; procedure sort(l,r:longint); var i,j,p,mid:longint; begin i:=l; j:=r; mid:=c[(l+r) div 2]; while i<j do begin while c[i]>mid do inc(i); while c[j]<mid do dec(j); if i<=j then begin p:=a[i]; a[i]:=a[j]; a[j]:=p; p:=c[i]; c[i]:=c[j]; c[j]:=p; inc(i); dec(j); end; end; if i<r then sort(i,r); if j>l then sort(l,j); end; begin assign(input,'missile.in'); reset(input); assign(output,'missile.out'); rewrite(output); readln(x1,y1,x2,y2); readln(n); for i:=1 to n do begin readln(x,y); a[i]:=sqr(x-x2)+sqr(y-y2); c[i]:=sqr(x-x1)+sqr(y-y1); end; sort(1,n); ans:=c[1]; for i:=2 to n do begin tot:=max(tot,a[i-1]); ans:=min(ans,c[i]+tot); end; writeln(ans); close(input); close(output); end.
第四道题因为题目太长,这里就不复制了,题意就是:在一个数列中,每个数与其他数组合都会产生一个值,然后你每次可以选一个数,选完到下一个人选,以此类推,你怎么选可以使得最后你选的数产生一个最大的默契值。“下一个人”的选法一定是:判断当前没被选过的哪个数与“你”选的数产生的默契值最高,则选这个数。
样例输入
6
5 28 16 29 27
23 3 20 1
8 32 26
33 11
12
样例输出
1
32
数据范围限制
提示
【输入输出样例说明】
首先小涵拿走 5 号武将;计算机发现 5 号武将和剩下武将中的 4 号默契值最高,于是拿走 4 号;小涵接着拿走 3 号;计算机发现 3、5 号武将之一和剩下的武将配对的所有组合中,5 号和1 号默契值最高,于是拿走 1号;小涵接着拿走 2 号;计算机最后拿走 6 号。在小涵手里的 2,3,5 号武将中,3 号和 5 号配合最好,默契值为 32,而计算机能推出的最好组合为 1 号和 6 号,默契值为 27。结果为小涵胜,并且这个组合是小涵用尽所有方法能取到的最好组合。
这道题目其实仔细分析一下,一定是先取的人赢,因为不管下一个人怎么选,虽然不能拿到最大值,但是次大值一定是先取的人,所以后取的人一定是输的。再进一步分析,我们可以得出,其实只要选一轮就可以得出结果了,因为题目最后是求一个最大值,并不是选的总和,所以只用进行一轮的选择来判断答案是什么就行了。那么如何得出答案呢?我们知道,当前不管你选哪个数,你不可能选到一个默契值最高的数,但是也因此你必定可以选到一个默契值次高的数,也就是你需要找出i与j组合产生的默契值是i这一行中次大的,同时i<>j就行了,也是一个贪心算法:
var a,c:array[1..100000]of longint; i,n,x,y,x1,x2,y1,y2,tot,ans:longint; function max(x,y:LOngint):LOngint; begin if x>y then exit(x) else exit(y); end; function min(x,y:LOngint):LOngint; begin if x>y then exit(y) else exit(x); end; procedure sort(l,r:longint); var i,j,p,mid:longint; begin i:=l; j:=r; mid:=c[(l+r) div 2]; while i<j do begin while c[i]>mid do inc(i); while c[j]<mid do dec(j); if i<=j then begin p:=a[i]; a[i]:=a[j]; a[j]:=p; p:=c[i]; c[i]:=c[j]; c[j]:=p; inc(i); dec(j); end; end; if i<r then sort(i,r); if j>l then sort(l,j); end; begin assign(input,'missile.in'); reset(input); assign(output,'missile.out'); rewrite(output); readln(x1,y1,x2,y2); readln(n); for i:=1 to n do begin readln(x,y); a[i]:=sqr(x-x2)+sqr(y-y2); c[i]:=sqr(x-x1)+sqr(y-y1); end; sort(1,n); ans:=c[1]; for i:=2 to n do begin tot:=max(tot,a[i-1]); ans:=min(ans,c[i]+tot); end; writeln(ans); close(input); close(output); end.