题目描述:
中文题,棋盘分割。
解题思路:
搜索所有划分可能。直接搜索肯定会超时,剪枝的思想来源于:计算方差里的变动项为分子的平方求和,而在划分下一格时,由于前面的格子面积已经固定下来,所以可以提前计算面积和平均面积差的平方和,这样就能够提前停止部分无效的搜索状态。
貌似有动规做的,递推公式里包含了五维数组。懒得看了。
代码:
#include <stdio.h>
#define N 16
#define MAX 100000000
long double sum=0, variance=0, min=MAX, avg_sq;
double chess[8][8];
int n;
double calc_sq(int li, int lj, int ri, int rj){
double s=0;
int i, j;
for(i=li; i<=ri; i++){
for(j=lj; j<=rj; j++){
s += chess[i][j];
}
}
return s;
}
void split(int t, int li, int lj, int ri, int rj){
double sq;
int i, j;
if(t==n-1){
sq = calc_sq(li,lj,ri,rj);// calc last square
variance += (sq-avg_sq)*(sq-avg_sq);
//variance = sqrt(variance/((double)n))
if( variance < min){
min = variance;
}
variance -= (sq-avg_sq)*(sq-avg_sq);
}else{
for(i=li; i<ri; i++){
//take bottom as next
sq = calc_sq(li,lj,i,rj);//calc up square
variance += (sq-avg_sq)*(sq-avg_sq);
if(variance < min)
split(t+1, i+1, lj, ri, rj);
variance -= (sq-avg_sq)*(sq-avg_sq);
//take up as next
if(t!=n-2){
sq = calc_sq(i+1, lj, ri, rj);//calc bottom square
variance += (sq-avg_sq)*(sq-avg_sq);
if(variance < min)
split(t+1,li,lj,i,rj);
variance -= (sq-avg_sq)*(sq-avg_sq);
}
}
for(j=lj; j<rj; j++){
//take left as next
sq = calc_sq(li,j+1,ri,rj);
variance += (sq-avg_sq)*(sq-avg_sq);
if(variance < min)
split(t+1,li,lj,ri,j);
variance -= (sq-avg_sq)*(sq-avg_sq);
//take right as next
if(t!=n-2){
sq = calc_sq(li,lj,ri,j);
variance += (sq-avg_sq)*(sq-avg_sq);
if(variance < min)
split(t+1,li,j+1,ri,rj);
variance -= (sq-avg_sq)*(sq-avg_sq);
}
}
}
}
main(){
int i, j;
scanf("%d",&n);
for(i=0;i<8;i++)
for(j=0;j<8;j++){
scanf("%lf",&chess[i][j]);
sum += chess[i][j];
}
avg_sq = sum/((double)(n));
split(0,0,0,7,7);
printf("%.3f\n", sqrt(min/((double)n)));
return 0;
}