将一个8*8的棋盘进行如下分割: 将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行)
图 9-5 棋盘分割示意图
原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成 n 块矩形棋盘,并使各矩形棋盘总分的均方差最小。 均方差 ,其中平均值 ,xi 为第i 块矩形棋盘的总分。 请编程对给出的棋盘及 n,求出 O'的最小值。
解题思路:
给一个矩形框可以横着分割,竖着分割,枚举横着和竖着分割的所有情况,每次横着分割右两种情况,保存上半段,继续分割下半段,保存下半段,继续分割上半段,每次竖着分割也有两种情况,保存左半端,继续分割右半段,保存右半段,继续分割左半段。
Input
第2行至第9行每行为8个小于100的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。
Output
Sample Input
3 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 3
Sample Output
1.633
import java.text.DecimalFormat;
import java.util.Scanner;
public class LX9_8 {
private static int[][] a=new int[8][8];//棋盘每个方格的分值
private static int n;//需要分割的矩形的个数
private static int[] size;//保存n个矩形的面积
private static double result=10;//保存最小的均方差
private static int total=0;//8*8棋盘分值的总和
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
size=new int[n];
//得到棋盘每个方格的分值
for(int i=0;i<8;i++)
{
for(int j=0;j<8;j++)
{
a[i][j]=sc.nextInt();
total+=a[i][j];
}
}
f(0,0,0,7,7);
DecimalFormat df = new DecimalFormat("0.000");
System.out.println(df.format(result));
}
/*第i次分割的所有情况 startx starty要分割的矩形棋盘起始位置的行和列 endx endy结束位置的行和列*/
public static void f(int i,int startx,int starty,int endx,int endy)
{
if(startx==endx&&endx==endy)//矩形的起始位置和终止位置是同一个位置,不能再分了,也就是说这种情况不能分成n个矩形
return;
if(i==n-2)//最后一次分割 两部分的分值之和都要保存
{
//横着分割的所有情况 j代表在该行下分割
for(int j=startx;j<=(endx-startx)/2+startx;j++)
{
//保存两部分
size[i]=jiSuan(startx,starty,j,endy);
size[i+1]=jiSuan(j+1,starty,endx,endy);
junFangCha();
}
//竖着分割的所有情况
for(int j=starty;j<=(endy-starty)/2+starty;j++)
{
//保存两部分
size[i]=jiSuan(startx,starty,endx,j);
size[i+1]=jiSuan(startx,j+1,endx,endy);
junFangCha();
}
}
else
{
//横着分割的所有情况 j代表在该行下分割
for(int j=startx;j<=(endx-startx)/2+startx;j++)
{
//保存上半部分,继续分割下半部分
size[i]=jiSuan(startx,starty,j,endy);
f(i+1,j+1,starty,endx,endy);
//保存下半部分,继续分割上半部分
size[i]=jiSuan(j+1,starty,endx,endy);;
f(i+1,startx,starty,j,endy);
}
//竖着分割的所有情况
for(int j=starty;j<=(endy-starty)/2+starty;j++)
{
//保存左半部分,继续分割右部分
size[i]=jiSuan(startx,starty,endx,j);
f(i+1,startx,j+1,endx,endy);
//保存右半部分,继续分割左部分
size[i+1]=jiSuan(startx,j+1,endx,endy);
f(i+1,startx,starty,endx,j);
}
}
}
//给出一个起始位置和结束位置的矩形,求出该矩形的分值和
public static int jiSuan(int startx,int starty,int endx,int endy)
{
int sum=0;
for(int i=startx;i<=endx;i++)
{
for(int j=starty;j<=endy;j++)
{
sum+=a[i][j];
}
}
return sum;
}
//给出n个矩形的分值和求出均方差
public static void junFangCha()
{
//求平均值
double m=total/(float)n;
double sum=0;
for(int i=0;i<n;i++)
{
double k=Math.pow(size[i]-m, 2);
sum+=k;
}
double j=Math.sqrt(sum/n);
if(j<result)
result=j;
}
}
问题:上传到poj上时说运行错误?
错误账目:
某财务部门结账时发现总金额不对头。很可能是从明细上漏掉了某1笔或几笔。如果已知明细账目清单,能通过编程找到漏掉的是哪1笔或几笔吗?
如果有多种可能,则输出所有可能的情况。
我们规定:用户输入的第一行是:有错的总金额。
接下来是一个整数n,表示下面将要输入的明细账目的条数。
再接下来是n行整数,分别表示每笔账目的金额。
要求程序输出:所有可能漏掉的金额组合。每个情况1行。金额按照从小到大排列,中间用空格分开。
比如:
用户输入:
6
5
3
2
4
3
1
表明:有错的总金额是6;明细共有5笔。
此时,程序应该输出:
1 3 3
1 2 4
3 4
为了方便,不妨假设所有的金额都是整数;每笔金额不超过1000,金额的明细条数不超过100。
思路:取n个数,然后尝试所以组合是否满足条件,满足则输出,不满足则继续尝试(类似碎纸机 poj书上的练习题)import java.util.Arrays;
import java.util.Scanner;
/*错误账目*/
public class WrongAccount {
private static int total;//错误的金额总数
private static int n;//账目笔数
private static int[] a;//n笔账目的金额
private static boolean[] flag;//标记账目是否在其中
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
total=sc.nextInt();
n=sc.nextInt();
a=new int[n];
flag=new boolean[n];
for(int i=0;i<n;i++)
{
a[i]=sc.nextInt();
}
//数组a排序从小到大
Arrays.sort(a);
for(int i=1;i<=n;i++)
{
f(i,0,0);
}
}
//num选几个数,cur当前选的第几个数,start当前数可以从该数开始选取
public static void f(int num,int cur,int start)
{
if(cur==num)//num个数选完成
{
jiSuan();
return;
}
if(start>=n)//没有选够数,但是已经没有数可以选
{
return;
}
for(int i=start;i<n;i++)
{
flag[i]=true;
f(num,cur+1,i+1);
flag[i]=false;
}
}
public static void jiSuan()
{
int sum=0;
for(int i=0;i<n;i++)
{
if(flag[i])//使用
{
sum+=a[i];
}
}
//结果等于目标数
if(sum==total)
{
for(int i=0;i<n;i++)
{
if(flag[i]==false)//没有使用
{
System.out.print(a[i]+" ");
}
}
System.out.println();
}
}
}