小易是这个游戏的VIP玩家,他拥有两项特权操作:
1、让平面内的所有怪物同时向任意同一方向移动任意同一距离
2、让平面内的所有怪物同时对于小易(0,0)旋转任意同一角度
小易要进行一次射击。小易在进行射击前,可以使用这两项特权操作任意次。
输入包括三行。 第一行中有一个正整数n(1 ≤ n ≤ 50),表示平面内的怪物数量。 第二行包括n个整数x[i](-1,000,000 ≤ x[i] ≤ 1,000,000),表示每只怪物所在坐标的横坐标,以空格分割。 第二行包括n个整数y[i](-1,000,000 ≤ y[i] ≤ 1,000,000),表示每只怪物所在坐标的纵坐标,以空格分割。
输出一个整数表示小易最多能消灭多少只怪物。
5 0 -1 1 1 -1 0 -1 -1 1 1
5
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scan = new Scanner(System.in); int n = scan.nextInt(); int x[] = new int[n]; int y[] = new int[n]; for (int i = 0; i < n; i++) x[i] = scan.nextInt(); for (int i = 0; i < n; i++) y[i] = scan.nextInt(); scan.close(); int maxShoot = 0;//在坐标轴上的点 if (n < 4) maxShoot = n; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { int X1 = x[j] - x[i]; int Y1 = y[j] - y[i]; for (int k = 0; k < n; k++) { if (k == i || k == j) continue; int count = 3; for (int l = 0; l < n; l++) { if (l == i || l == j || l == k) continue; int X2 = x[l] - x[k]; int Y2 = y[l] - y[k]; int X3 = x[l] - x[i]; int Y3 = y[l] - y[i]; if (X1 * X2 + Y1 * Y2 == 0 || X1 * Y3 == X3 * Y1) count++; } if (count > maxShoot) maxShoot = count; } } } System.out.println(maxShoot); } }
题目等价于,找一个十字架能够尽可能多的覆盖所有节点。
考虑到一根线至少能够覆盖到两个点,再加一根垂直于这条线至少能够覆盖3个点,在此基础上进行遍历。对任意三个点,我们选择其中两个点做一条直线(三种情况),对于第三个点,我们做一条垂线到这条直线上。这样的十字架已经经过了三个点。对于剩下的点,我们判断是否在这个十字架上。要判断是否在十字架上,首先判断是否和第一条直线在同一条直线上。否则,判断这个点和第三个点所构成的直线是否和第二条直线垂直。
当点数小于等于3个点,则可以把所有点都覆盖到。
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
struct point{
int x = 0;
int y = 0;
};
bool is_sameline(point p1, point p2, point p3){
return ((p1.x - p2.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p2.y)) == 0;
}
bool is_vertical(point p1, point p2){
return (p1.x * p2.x + p1.y * p2.y) == 0;
}
bool is_vertical(point p1, point p2, point p3, point p4){
point v1, v2;
v1.x = p1.x - p2.x;
v1.y = p1.y - p2.y;
v2.x = p3.x - p4.x;
v2.y = p3.y - p4.y;
return is_vertical(v1, v2);
}
int main()
{
int n, ret = 0;
cin >> n;
point inputs[n];
for (int i = 0; i < n; i++)
cin >> inputs[i].x;
for (int i = 0; i < n; i++)
cin >> inputs[i].y;
if (n < 4)
{
cout << n << endl;
return 0;
};
vector<int> select = {1, 1, 1};
for (int i = 0; i < n - 3; i++)
select.push_back(0);
do
{
vector<point> shizi;
for (int i = 0; i < n; i++)
{
if (select[i])
{
shizi.push_back(inputs[i]);
}
}
vector<vector<point>> status;
status.push_back({shizi[0], shizi[1], shizi[2]});
status.push_back({shizi[0], shizi[2], shizi[1]});
status.push_back({shizi[1], shizi[2], shizi[0]});
for (auto points : status)
{
int count = 0;
for (int i = 0; i < n; i++)
{
if (!select[i])
{
if (is_sameline(points[0], points[1], inputs[i]))
count++;
if (is_vertical(points[0], points[1], points[2], inputs[i]))
count++;
}
}
ret = max(ret, count);
}
} while (prev_permutation(select.begin(), select.end()));
cout << ret + 3 << endl;
return 0;
}
思路参考@littlebee
本套8道题的C++代码已挂到了我的GitHub(https://github.com/shiqitao/NowCoder-Solutions)
#include <iostream>
using namespace std;
int main()
{
int n; cin >> n;
int *x = new int[n];
int *y = new int[n];
int *dx = new int[n*n];
int *dy = new int[n*n];
for (int i = 0; i < n; i++) {
cin >> x[i];
}
for (int i = 0; i < n; i++) {
cin >> y[i];
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
dx[i*n + j] = x[i] - x[j];
dy[i*n + j] = y[i] - y[j];
}
}
int max = -1, temp;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
for (int p = 0; p < n; p++) {
if (p == i || p == j || dy[i*n + j] * dx[i*n + p] == dy[i*n + p] * dx[i*n + j]) continue;
temp = 0;
for (int q = 0; q < n; q++) {
if (dy[i*n + j] * dx[i*n + q] == dy[i*n + q] * dx[i*n + j] || dy[i*n + j] * dy[p*n + q] == -dx[i*n + j] * dx[p*n + q]) {
temp++;
}
}
max = max>temp ? max : temp;
}
}
}
max = max == -1 ? n : max;
cout << max;
delete[] x;
delete[] y;
delete[] dx;
delete[] dy;
return 0;
}
#include<stdio.h> #define max(a,b) a>b?a:b const int maxn=55; int dx[maxn][maxn],dy[maxn][maxn],x[maxn],y[maxn]; int main(){ int n,i,j,k,q,res,Max=-1; for(scanf("%d",&n),i=0;i<n;i++) scanf("%d",&x[i]); for(i=0;i<n;i++) scanf("%d",&y[i]); for(i=0;i<n;i++) for(j=0;j<n;j++) dx[i][j]=x[j]-x[i],dy[i][j]=y[j]-y[i]; for(i=0;i<n;i++) for(j=i+1;j<n;j++) for(k=0;k<n;k++) if(k!=i&&k!=j&&dy[i][j]*dx[i][k]!=dy[i][k]*dx[i][j]){ for(q=0,res=0;q<n;q++) if(dy[i][j]*dx[i][q]==dy[i][q]*dx[i][j] ||dy[i][j]*dy[k][q]==-dx[i][j]*dx[k][q]) res++; Max=max(Max,res); } printf("%d\n",Max+1?Max:n); }
clean and concise python solution
n = int(input()) x = list(map(int,input().strip().split())) y = list(map(int,input().strip().split())) res = min(n,3) for i in range(n): for j in range(i+1,n): dy1 = y[j] - y[i] dx1 = x[j] - x[i] for k in range(j+1,n): cnt = 3 for l in range(n): if l == i or l == j or l == k: continue dy2 = y[k] - y[l] dx2 = x[k] - x[l] dy3 = y[i] - y[l] dx3 = x[i] - x[l] if dx1*dx2 + dy1*dy2 == 0 or dx1*dy3 == dx3*dy1: cnt += 1 res = max(res,cnt) print(res)
#include <stdio.h>
#include <set>
#include <map>
using namespace std;
int n;
int x[50];
int y[50];
set<double> factors;
int targetNum(int factor){
double offsetP[50];
double offsetN[50];
map<double,int> tmpOffsetPs;
map<double,int> tmpOffsetNs;
if (factor==0) {
for(int i=0;i<n;i++){
offsetP[i]=y[i];
tmpOffsetPs[offsetP[i]]++;
offsetN[i]=x[i];
tmpOffsetNs[offsetN[i]]++;
}
}
else{
for(int i=0;i<n;i++){
offsetP[i]=y[i]-factor*x[i];
tmpOffsetPs[offsetP[i]]++;
offsetN[i]=y[i]+1/factor*x[i];
tmpOffsetNs[offsetN[i]]++;
}
}
int offsetPNum=0;
double offsetPVal[50];
int offsetPValNum=0;
int offsetNNum=0;
double offsetNVal[50];
int offsetNValNum=0;
map<double,int>::iterator it;
for (it=tmpOffsetPs.begin(); it!=tmpOffsetPs.end(); it++) {
if (offsetPNum<(it->second)) {
offsetPNum=(it->second);
offsetPValNum=1;
offsetPVal[0]=(it->first);
}
else if (offsetPNum==(it->second)){
offsetPVal[offsetPValNum]=(it->second);
offsetPValNum++;
}
}
for (it=tmpOffsetNs.begin(); it!=tmpOffsetNs.end(); it++) {
if (offsetNNum<(it->second)) {
offsetNNum=(it->second);
offsetNValNum=1;
offsetNVal[0]=(it->first);
}
else if (offsetNNum==(it->second)){
offsetNVal[offsetNValNum]=(it->second);
offsetNValNum++;
}
}
int returnVal=offsetPNum+offsetNNum;
for (int j=0; j<offsetPValNum; j++) {
for (int k=0; k<offsetNValNum; k++) {
int tmpMask=0;
for (int i=0; i<n; i++) {
if (offsetP[i]==offsetPVal[j] && offsetN[i]==offsetNVal[k]) {
tmpMask=1;
break;
}
}
if (tmpMask==0) {
return returnVal;
}
}
}
return returnVal-1;
}
void work(){
if (n==1) {
printf("%d",1);
return;
}
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
if (x[i]==***>
factors.insert(0);
}
else
factors.insert(double(y[i]-y[j])/(x[i]-***>
}
}
int result=0;
set<double>::iterator it;
for (it=factors.begin(); it!=factors.end(); it++) {
int tmp = targetNum(*it);
result = result>=tmp ? result : tmp;
}
printf("%d",result);
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&x[i]);
}
for(int i=0;i<n;i++){
scanf("%d",&y[i]);
}
work();
}
本题的情况思路比较清晰,主要借助直线垂直与平行的情况来确定点数, 借助多重循环扫描寻找垂直和平行 主要依据是:两条垂直线可以通过以下变换转移至坐标轴位置,从而怪物被消灭 a)将垂直线整体平移,至垂直线交点为坐标轴原点 b)将两直线整体绕原点旋转一定度数,至两线分别与x,y轴重合 使用循环扫描时两种情况需要注意:1)当怪物少于4时,点数=怪物数量; 2)当所以怪物均共线时,点数=n 下附代码 #include <iostream> using namespace std; const int N = 51; int XM[N]; int YM[N]; int main() { int n; cin >> n; for (int i = 0; i < n; i++) { cin >> XM[i]; } for (int i = 0; i < n; i++) { cin >> YM[i]; } int flag = 0; int max = 0; int t = 0; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) for (int k = 0; k < n; k++) { if (i!=j&&i!=k&&j!=k) { if ((XM[i] - XM[j])*(YM[i] - YM[k]) != (XM[i] - XM[k])*(YM[i] - YM[j])) //不共线 { flag = 1; t += 3; for (int m = 0; m < n; m++) { //点不重复 if (i != m&&j != m&&k != m) { if ((XM[i] - XM[j])*(YM[i] - YM[m]) == (XM[i] - XM[m])*(YM[i] - YM[j])) //共线 t++; else if ((XM[i] - XM[j])*(XM[k] - XM[m]) == (YM[i] - YM[j])*(YM[m] - YM[k])) t++; } } if (t > max) max = t; t = 0; } } } if (n < 4) max = n; if (!flag) max = n; cout << max; return 0; }
#include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std; int main(){ int n; cin >> n; vector<int> xs(n,0), ys(n,0); for(int i=0; i<n; i++) cin >> xs[i]; for(int i=0; i<n; i++) cin >> ys[i]; int ret = min(3, n); // 过point[i] 作关于 point[k] --- point[l] 的垂线 for(int i=0; i<n; i++){ for(int j=0; j<n; j++){ if(j==i) continue; // 避免重复 for(int k=j+1; k<n; k++){ // 交换 j,k 直线不变 int dx = xs[j]-xs[k], dy = ys[j]-ys[k]; // j--k 方向向量 int tmp = 0; for(int l=0; l<n; l++){ int ax1 = xs[l]-xs[i], ay1 = ys[l]-ys[i]; // l--i 方向向量 int ax2 = xs[l]-xs[j], ay2 = ys[l]-ys[j]; // l--j 方向向量 if(ax1*dx+ay1*dy==0 || ax2*dy-ay2*dx==0) tmp++; // 共线关系转换为垂直关系 } ret = max(ret, tmp); } } } cout << ret << endl; }
#同样四层for循环,python超时了,太不友好了 n = int(input().strip('\n')) x = [int(i) for i in input().strip('\n').split(' ')] y = [int(i) for i in input().strip('\n').split(' ')] max_count = 0 for i in range(n): for j in range(n): if j == i: continue x1 = x[j] - x[i] y1 = y[j] - y[i] for k in range(n): if k == i or k == j: continue count = 3 for t in range(n): if t == i or t == j or t == k: continue x2 = x[t] - x[k] y2 = y[t] - y[k] if x1 * x2 + y1 * y2 == 0 or (x[t] - x[i]) * y1 == (y[t] - y[i]) * x1: count += 1 max_count = max(max_count, count) if n <= 3: max_count = n print(max_count)
根据 littlebee的解析,使用python编写通过
n=int(input())
x_list=[int(x) for x in input().split(' ')]
y_list=[int(x) for x in input().split(' ')]
def run(x_list,y_list,n):
max_num=0
if n <= 3:
return n
else:
flag_ABC_exits = 0 #是否存在ABC三点不共线的情况
for i in range(n):
for j in range(i + 1, n):
dxAB = x_list[i] - x_list[j] # AB
dyAB = y_list[i] - y_list[j]
for k in range(j + 1, n):
dxAC = x_list[i] - x_list[k]
dyAC = y_list[i] - y_list[k]
if dxAC * dyAB == dyAC * dxAB: # ABC不共线
continue
num = 0
flag_ABC_exits = 1
for m in range(n):
if m == i or m == j or m == k:
continue
dxAD = x_list[i] - x_list[m] # AD
dyAD = y_list[i] - y_list[m]
dxCD = x_list[k] - x_list[m] # CD
dyCD = y_list[k] - y_list[m]
if dxAD * dyAB == dxAB * dyAD or dxCD * dxAB + dyCD * dyAB == 0: #D点在AB上或CD垂直AB
num += 1
num += 3
if num > max_num:
max_num = num
if not flag_ABC_exits:
num = 0
for m in range(n):
if m == i or m == j:
continue
dxAD = x_list[i] - x_list[m] # AD
dyAD = y_list[i] - y_list[m]
if dxAD * dyAB == dxAB * dyAD:
num += 1
num += 2
if num > max_num:
max_num = num
if max_num == n:#如果max_num等于n,没有必要再循环了,跳出
return n
return max_num
print(run(x_list,y_list,n))
/*
* 参考大神的解题思路:https://www.nowcoder.com/questionTerminal/d3f26db0325444078717cc802e0056d8
*
* 使用四次循环,分别用于挑选不同的四个点;
* 第一次和第二次循环挑选好为x轴的直线,第三次和第四次用于挑选好y轴;
* 然后在整个遍历的过程中选择最大的值
* */
public class MaxShot {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
int[] x = new int[n];
int[] y = new int[n];
// 录入所有点的坐标值
for (int i = 0; i < n; i++) {
x[i] = scanner.nextInt();
}
for (int i = 0; i < n; i++) {
y[i] = scanner.nextInt();
}
int maxShot = 0;
if (n < 4) {
maxShot = n;
} else {
// 确定x轴
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
int x1 = x[j] - x[i];
int y1 = y[j] - y[i];
for (int k = 0; k < n; k++) {
// 确定y轴的一个点
if (k == i || k == j) {
continue;
}
int tmp = 3;
// 变换另一个点
for (int l = 0; l < n; l++) {
if (l == i || l == j || l == k) {
continue;
}
int x2 = x[l] - x[i];
int y2 = y[l] - y[i];
int x3 = x[l] - x[k];
int y3 = y[l] - y[k];
// 该点在x轴或者y轴上添加进来
if (x1 * y2 == x2 * y1 || x1 * x3 + y1 * y3 == 0) {
tmp++;
}
maxShot = Math.max(maxShot, tmp);
}
}
}
}
}
System.out.println(maxShot);
}
}
}
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n], b = new int[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt();
}
for (int i = 0; i < n; i++) {
b[i] = sc.nextInt();
}
if (n < 3) {
System.out.println(n);
return;
}
int max = 3;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
double k1 = (b[i] - b[j]) / (a[i] - a[j] + 0.0);
double b1 = b[i] - k1 * a[i];
for (int k = j + 1; k < n; k++) {
int count = 0;
for (int l = k + 1; l < n; l++) {
if (k1 * a[l] + b1 == b[l]) {
count++;
continue;
}
double k2 = (b[l] - b[k]) / (a[l] - a[k] + 0.0);
if (k2 * k1 == -1)
count++;
}
max = Math.max(max, count);
}
}
}
System.out.println(max);
}
}