題目來源:http://acm.fzu.edu.cn/problem.php?pid=1515福州大學OJ15
題目大意,有一個立方體的盒子,給出對角兩個頂點的座標,在這個盒子裡,有N個點,其中N<=6.在其中任何一個點上放上氣球,該氣球自動膨脹直到碰到盒壁或其它氣球,必須等一個氣球擴充完畢才能擴充第二個氣球,按照怎樣的順序在這N個點上放上氣球,才能使氣球的總體積最大,題目要求輸出剩餘體積,四捨五入取整.
因為只有6個氣球,全排列共有6!=720種膨脹方案.因為情況較少,很容易想到枚舉.用DFS求出每種膨脹方案的順序,然後再依次求得每個氣球到6個面以及其它氣球的距離,取其中的最小值作為半徑.有一個要注意的地方就是如果某點沒有氣球,是可以被包含在別的氣球內部的,顯然,這時候該點氣球所佔的體積為0,一開始沒有考慮到這個問題,WA了兩次...上代碼..
import java.util.Arrays;<br />import java.util.Scanner;<br />public class Main{<br />public static void main(String []args){<br />new Main();<br />}<br />int total;<br />int[] visit;<br />int[] result;<br />double max;<br />Point c1,c2,ps[];<br />int count=0;<br />public Main(){<br />Scanner sc=new Scanner(System.in);<br />while(sc.hasNext()){<br />total=sc.nextInt();<br />c1=new Point(sc.nextDouble(),sc.nextDouble(),sc.nextDouble());//盒子的兩個對角座標<br />c2=new Point(sc.nextDouble(),sc.nextDouble(),sc.nextDouble());<br />ps=new Point[total];//氣球的座標<br />for(int i=0;i<total;i++){<br />ps[i]=new Point(sc.nextDouble(),sc.nextDouble(),sc.nextDouble());<br />}<br />//枚舉氣球膨脹的順序;<br />visit=new int[total];<br />Arrays.fill(visit, 0);<br />result=new int[total];<br />max=0;<br />dfs(0);//全排列total個數,結果放入result中<br />double v=Math.abs((c1.x-c2.x)*(c1.y-c2.y)*(c1.z-c2.z));<br />System.out.printf("%.0f",v-max);//輸出最小的剩餘面積<br />System.out.println();<br />}<br />}<br />private void dfs(int count) {<br />for(int i=0;i<total;i++){<br />if(visit[i]==0){<br />visit[i]=1;<br />result[count]=i;<br />if(count==total-1){<br />cal();//全排列到最後一個數時計算當前的面積<br />}else{<br />dfs(count+1);<br />}<br />visit[i]=0;<br />}<br />}<br />}<br />private void cal() {<br />double totalv=0;//所有圓的面積和<br />for(int i=0;i<total;i++){<br />ps[i].r=0;<br />}<br />for(int i=0;i<total;i++){<br />int now=result[i];<br />//到面的最短距離<br />double x1=Math.min(Math.abs(ps[now].x-c1.x),Math.abs(ps[now].x-c2.x));<br />double x2=Math.min(Math.abs(ps[now].y-c1.y),Math.abs(ps[now].y-c2.y));<br />double x3=Math.min(Math.abs(ps[now].z-c1.z),Math.abs(ps[now].z-c2.z));<br />ps[now].r=Math.min(x1,Math.min(x2, x3));<br />//到其它點的距離<br />for(int j=0;j<total;j++){<br />if(now==j||ps[j].r==0)continue;//注意,可以將其它點包含於圓內<br />double x4=Math.sqrt((ps[now].x-ps[j].x)*(ps[now].x-ps[j].x)+(ps[now].y-ps[j].y)*(ps[now].y-ps[j].y)+(ps[now].z-ps[j].z)*(ps[now].z-ps[j].z))-ps[j].r;<br />//當點在該圓外時,半徑等於到邊和到該圓的距離的較小值<br />ps[now].r=Math.min(ps[now].r, x4);<br />//如果點在該圓內,半徑置為0<br />if(ps[now].r<0)ps[now].r=0;<br />}<br />totalv+=4.0d/3.0d*Math.PI*ps[now].r*ps[now].r*ps[now].r;<br />}<br />if(totalv>max)max=totalv;<br />}<br />}<br />class Point{<br />double x,y,z;//座標<br />double r;//半徑<br />public Point(double x,double y,double z){<br />this.x=x;this.y=y;this.z=z;<br />}<br />}