第20次CSP认证202009-4 星际旅行

    科技2024-08-06  69

    第 20 次 CSP认证 202009-4 星际旅行

    1.写在前面

    考试时候没做出来,第三题debug太久,md 现在75分,超时,不知道哪里有改进空间,可能是算法不太行,数学好菜啊

    2.思路

    想法是把两个点和圆心构成一个三角形,三角形的三边定义成 moa,mob,juli即向量a的模,向量b的模,ab两点的距离。用向量乘积的定理,可以求出两个向量的夹角jiaodu,用面积公式计算出高gao,计算高是否在三角形内部就要计算是否是钝角三角形,钝角三角形一定不在球内,返回距离。判断高与半径的关系,不在球内则返回距离。 若两点连线经过球,则路径是圆弧加两个切线长。

    3.代码

    import java.util.Scanner; public class Main { public static int m; public static int n; public static int r; public static double getans(int[] point1,int[] point2) { int i=0; int xiangliangji=0; double moji=0; double moa=0,mob=0; double juli=0; double jiaodu=0; double gao=0; double ret=0; for(i=0;i<n;i++) { xiangliangji+=point1[i]*point2[i]; moa+=point1[i]*point1[i]; mob+=point2[i]*point2[i]; juli+=(point1[i]-point2[i])*(point1[i]-point2[i]); } moa=Math.sqrt(moa); mob=Math.sqrt(mob); juli=Math.sqrt(juli); moji=moa*mob; if(xiangliangji/moji<-1||xiangliangji/moji>1) moji=Math.round(moji); jiaodu=Math.acos(xiangliangji/moji); gao=moa*mob*Math.sin(jiaodu)/juli; double jiaoa=Math.asin(mob*Math.sin(jiaodu)/juli); double jiaob=Math.asin(moa*Math.sin(jiaodu)/juli); if((jiaoa+jiaodu)<Math.PI/2||(jiaob+jiaodu)<Math.PI/2) { return juli; } if(gao>r) return juli; jiaodu-=Math.acos(r/moa); jiaodu-=Math.acos(r/mob); double juli1,juli2; if(moa>r) juli1=Math.sqrt(moa*moa-r*r); else juli1=0; if(mob>r) juli2=Math.sqrt(mob*mob-r*r); else juli2=0; ret=juli1+juli2+r*jiaodu; return ret; } public static void main(String[] args) { Scanner sc=new Scanner(System.in); n=sc.nextInt(); m=sc.nextInt(); int[][] inp=new int[m][n]; int[] cen=new int[n]; double[][] ans=new double[m][m]; r=sc.nextInt(); int i,j; for(i=0;i<n;i++) cen[i]=sc.nextInt(); for(i=0;i<m;i++) { for(j=0;j<n;j++) { inp[i][j]=sc.nextInt()-cen[j]; } } double ret=0; for(i=0;i<m;i++) { ret=0; for(j=0;j<i;j++) { ret+=ans[i][j]; } ans[i][i]=0; for(j=i+1;j<m;j++) { ans[i][j]=getans(inp[i],inp[j]); ans[j][i]=ans[i][j]; ret+=ans[i][j]; } System.out.println(ret); } } }
    Processed: 0.009, SQL: 8