标签:ini div stdio.h max math inf 考点 算法 生日
高中的时候好像什么都没学会的样子,提到搜索脑子里云里雾里一般。还能怎么着,练呗。
找到了一道dfs基础题,http://poj.org/problem?id=1190
果然是完全没有思路,参照大佬的题解,弄懂了大佬的思路。
1 //生日蛋糕 2 //poj 1190 3 #include<stdio.h> 4 #include<math.h> 5 #define INF 1000000 6 int mins[21],minv[21];//从第一层到第i层的最小体积minv和最小面积mins 7 #define min(a,b) ((a)<(b)?(a):(b)) 8 int n,m,best; 9 void init(){ 10 int i; 11 for(i=1;i<21;i++){ 12 mins[i]=mins[i-1]+2*i*i;//因为半径和高必须是正整数,又要递增,所以i作为 13 minv[i]=minv[i-1]+i*i*i; //第i层的半径和高显然是最小的情况。 14 } 15 } 16 17 //核心算法:搜索。从第m层开始往上搜索,一直到第0层结束。 18 // deep表示该层层数,sums是从m到deep+1得到的表侧面积,sumv是体积,r是deep+1的半径,h是deep+1的高度 19 void dfs(int deep,int sums,int sumv,int r,int h){ 20 if(deep==0){ 21 if(sumv==n&&sums<best)best=sums; 22 return; 23 } 24 if(sums+mins[deep]>best||sumv+minv[deep]>n||2*(n-sumv)/r+sums>=best)return; 25 //几个剪枝 26 //第一跟第二:表面积显然大于最优解或者是体积显然超过n 27 //第三个:n-sumv=h[1]*r[1]*r[2]+……+h[deep]*r[deep]*r[deep]<h[1]*r[1]*r+……+h[deep]*r[deep]*r 28 //两边同除r,*2,可以化为这样的形式 29 int i,j,maxh; 30 for(i=r-1;i>=deep;i--){//i是遍历deep层的半径,从最大到最小 31 if(deep==m)sums=i*i;//sums的初值 32 maxh =min((n-sumv-minv[deep-1])/(i*i),h-1);//从这两个数中寻找maxh的最大值,这两个都是顶点 33 for(j=maxh;j>=deep;j--)dfs(deep-1,sums+2*i*j,sumv+i*i*j,i,j); 34 } 35 } 36 main(){ 37 best=INF; 38 scanf("%d%d",&n,&m); 39 dfs(m,0,0,sqrt(n)+1,n+1);//初始条件m+1层的半径为h等于1时得到的半径,h是r等于1时得到的半径。 40 if(best==INF)printf("0\n"); 41 else printf("%d\n",best); 42 return 0; 43 }
这道题的主要考点应该是第三处剪枝(大佬是这么说的),但是与我而言,我连最基础的搜索的板子都不会。还能怎么着,练呗。
标签:ini div stdio.h max math inf 考点 算法 生日
原文地址:https://www.cnblogs.com/liuxinyu/p/9372781.html