13,100
社区成员
发帖
与我相关
我的任务
分享
import java.util.Random;
public class SuijiShuzu {
private static int randMax = 15000, randMin = 200;
private static int arrayDimension = 31;
private static int x[]={1910,4218,5767,6416,8637,15614,8948,
17723,13698,9867,35086,16705,20596,50504,53689,
23548,25478,20346,18336,24645,68070,10552,10024,
17810,13219,14645,20105,13904,24035,20474,43073};
private static int y[]={91009,14869,15459,18354,19054,22573,33566,19850,
26725,22593,15877,34075,23895,24990,59862,48301,
11417,13657,10059,5466,18403,36273,8326,14760,
8573,5079,4144,6197,1524,2042,670};
public static void main(String[] args) {
System.out.println("sum of array x:"+sum(x)+", sum of array y:"+sum(y));
Random rand = new Random(System.currentTimeMillis());
int[][] rain = new int[arrayDimension][arrayDimension];
// 逆向思维啊
// 第一步,既然最小值是200,则,先按要求给可能有数的点都填上200再说
//满足第一点约束:rain数组里面第一行只有一个元素,第二行有2个元素,第三行有3个元素。以此类推
for (int i = 0; i < arrayDimension; i++) {
for (int j = 0; j <= i; j++) {
rain[i][j] = randMin;
}
}
// 第二步,把已经放到数组中的200,按行、列之和从x、y两个数组中减去
for (int i = 0; i < arrayDimension; i++) {
x[i] -= (i + 1) * randMin;
y[arrayDimension - i - 1] -= (i + 1) * randMin;
}
//第三步,把X数组中的每一个元素x[i],按照对应的y[j]/sum[y]的比例,平均分布到该行的各数据点,
//在分布的过程中,增加一定的随机性(正负50,可以调)
for (int i = 0; i < arrayDimension; i++) {
int currentX=x[i];
int sumY=sum(y,0,i+1);
for (int j = 0; j <= i; j++) {
long share=(long)(1L*currentX*y[j])/(long)sumY;
int nextRand=rand.nextInt(100)-50;
long preResult=rain[i][j]+share+nextRand;
if (preResult>randMin && preResult<randMax){
share+=nextRand;
}
rain[i][j] += share;
x[i]-=share;
y[j]-=share;
}
}
// 第四步,我们把X数组中剩下的值,分发到对应行的随机列上,分发到某列的同时,我们在这个列对应的y数组中,也减去1,
// 经过这一步,可以保证X数组全部为0,也就是,每行的和 符合要求。
int count=0;
for (int i = x.length-1; i >=0; i--) {
while (x[i] != 0) {
// 这里随机产生的是一个坐标值x,如果rain[i][x]<randMax,则rain[i][x]++
int nextRand = rand.nextInt(i+1);
if (rain[i][nextRand] < randMax && rain[i][nextRand]>randMin) {
if (x[i]>0){
rain[i][nextRand]++;
x[i]--;
y[nextRand]--;
}else{
rain[i][nextRand]--;
x[i]++;
y[nextRand]++;
}
}
}
}
//最后一步,由于行已经符合要求,但列可能不符合要求,
//所以我们要根据y数组中当前值(可能有负数)来做列迁移(挖高补低),一直到y数组中也全部为0
for(int i=0; i<y.length;i++){
while (y[i]>0){//如果当前的列和值小于0,则说明当前列还需要做行调整
int negIndex=findNegative(y);//首先找到一个列和值为负数的下表,就在这两列之间调整
if (negIndex<0){
System.out.println("终于完事儿了!");
break;
}else{
int adjustRowIndex=negIndex;
if (y[negIndex]+y[i]>=0){
rain[adjustRowIndex][negIndex]+=y[negIndex];
rain[adjustRowIndex][i]-=y[negIndex];
y[i]+=y[negIndex];
y[negIndex]=0;
}else{
rain[adjustRowIndex][negIndex]-=y[i];
rain[adjustRowIndex][i]+=y[i];
y[negIndex]+=y[i];
y[i]=0;
}
}
}
}
System.out.println("随机数组:");
dump(rain);
System.out.println("sum of array x:"+sum(x)+", sum of array y:"+sum(y));
}
private static int findNegative(int[] array){
for(int i=0; i<array.length;i++){
if (array[i]<0){
return i;
}
}
return -1;
}
private static void dump(int[][] array) {
for (int i = 0; i < array.length; i++) {
dump(array[i]);
}
}
private static void dump(int[] array) {
for (int j = 0; j < array.length; j++) {
System.out.print(array[j] + "\t");
}
System.out.println();
}
private static int sum(int[] array){
int sum=0;
for(int i=0; i<array.length;i++){
sum+=array[i];
}
return sum;
}
private static int sum(int[] array,int start, int end){
int sum=0;
for(int i=start;i<end;i++){
sum+=array[i];
}
return sum;
}
private static int min(int a, int b){
return a<b?a:b;
}
}