搜索算法 - 桶和石头

时间:2015-06-16 20:07:35

标签: java algorithm

您好我正在搜索算法来解决以下问题:

有n个桶和y石头,可以扔进水桶。在每个学生用随机水桶投掷石头x次后,水桶有不同的石头数。现在教授拿了100张Post-It并随机将这些贴子放在桶上。他说:“每个Post-Id都表示所有水桶中石头数量的百分之一,所以如果水桶A有10个石柱,那么如果Y = 100(整块石头的数量),它最终会有10块石头。请更改水桶中的石块数量,因此每个水桶中都有最大的石头。转移量最小的团队(见下面的TransferAction.class)赢得啤酒!“

这应该是一个常见的分布问题,但我不知道如何解决它。我必须找到一个具有最小更改操作的算法,因此我会采用一些摘要统计信息来找出一些运行/试用/时间的最佳算法。

任何人都可以帮助或指出我最好的算法吗?

有一些限制 :因此无法将所有石头放在一个桶中,然后将适量的金额放回去!最小的意思是,铲斗A可以在铲斗B中放置一些石头,但随后斗B不能放任何石头就是斗A了。

到目前为止,这是我的代码:

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;

import org.apache.commons.math3.stat.descriptive.SummaryStatistics;

public class Main {
    private static final float Take_Over__Percent_Maximum = 100;

    private static Random RANDOM = new Random();

    public static void main(String[] args) {

        List<Integer> averageSizeList = new ArrayList<Integer>();

        int runs = 1000;
        for (int i = 0; i < runs ; i++) {
            List<TransferAction> transferActions = doSingleRun();
            averageSizeList.add( transferActions.size());
            System.out.println("The size of transfers:" + transferActions.size());
        }

        calculateAverage(averageSizeList);

    }

    private static void calculateAverage(List<Integer> averageSizeList) {

        System.out.println();
        double[] observed = averageSizeList.stream().mapToDouble(i->i).toArray();
        SummaryStatistics sampleStats = new SummaryStatistics();

        for (int i = 0; i < observed.length; i++) {
            sampleStats.addValue(observed[i]);
        }

        System.out.println(sampleStats.toString());

    }

    private static List<TransferAction> doSingleRun() {
        // create some buckets
        List<Bucket> bucketList = new ArrayList<Bucket>();
        int numberOfBuckets = 5;
        float percentageOfAllStonesInBucket = Take_Over__Percent_Maximum
                / numberOfBuckets;
        for (int i = 0; i < numberOfBuckets; i++) {
            Bucket bucket = new Bucket(percentageOfAllStonesInBucket);
            bucketList.add(bucket);
        }

        // now fill buckets with stones
        int fillActions = 100;
        List<FillAction> fillActionsList = new ArrayList<FillAction>();
        for (int i = 0; i < fillActions; i++) {
            UUID randomBucketId = bucketList.get(
                    RANDOM.nextInt(bucketList.size())).getId();
            BigDecimal randomAmount = new BigDecimal(RANDOM.nextLong());
            FillAction fillAction = new FillAction(randomAmount, randomBucketId);
            fillActionsList.add(fillAction);
        }

        // now try to change the amount of stones in the buckets, so in the end
        // every bucket has the right percent of all stones in it
        return calculate(bucketList,fillActionsList);

    }

    private static List<TransferAction> calculate(List<Bucket> bucketList,
            List<FillAction> fillActionsList) {     
        List<TransferAction> transferActions = new ArrayList<TransferAction>();

        // the magic should be done here
        //...
        //...


        //now every bucket has maximum percent of all stone or equal stones
        return transferActions;
    }

}

桶类:

import java.util.UUID;

public class Bucket {

    private final UUID id;
    private float percentTakeOver;

    public Bucket(float percentTakeOver) {
        this.id = UUID.randomUUID();
        if (percentTakeOver > 100) {
            this.percentTakeOver = 100;
        } else if (percentTakeOver < 0) {
            this.percentTakeOver = 0;
        } else {
            this.percentTakeOver = percentTakeOver;
        }
    }

    public float getPercentTakeOver() {
        return percentTakeOver;
    }

    public void setPercentTakeOver(float percentTakeOver) {
        this.percentTakeOver = percentTakeOver;
    }

    public UUID getId() {
        return id;
    }
}

FillAction类FillAction类(最好的算法没有很多FillActions):

import java.math.BigDecimal;
import java.util.UUID;

public class FillAction {

    private final BigDecimal amount;
    private final UUID bucketID;

    public FillAction(BigDecimal amount, UUID bucketID) {
        this.amount = amount;
        this.bucketID = bucketID;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public UUID getBucketID() {
        return bucketID;
    }

}

下一步:

import java.math.BigDecimal;
import java.util.UUID;

public class TransferAction {

    private final UUID fromBucket;
    private final UUID toBucket;
    private final BigDecimal amount;

    public TransferAction(UUID fromBucket, UUID toBucket, BigDecimal amount) {
        this.fromBucket = fromBucket;
        this.toBucket = toBucket;
        this.amount = amount;
    }

    public UUID getFromBucket() {
        return fromBucket;
    }

    public UUID getToBucket() {
        return toBucket;
    }

    public BigDecimal getAmount() {
        return amount;
    }
}

1 个答案:

答案 0 :(得分:1)

我不知道你的意思,但我会以我的理解为例,尝试理解你的要求。

可用石头= x15

Buckets = A + B + C

铲斗容量A = 1 / 3~33,33% - >这意味着15 *(1/3)= 5石头

铲斗容量B = 1 / 3~33,33% - >这意味着15 *(1/3)= 5石头

铲斗容量C = 1 / 3~33,33% - >这意味着15 *(1/3)= 5石头

Bucket中的初始石头(符号0):

 A=4  | B=8   | C=3
##### | ##### | ##### 
# 0 # | # 0 # | # 0 #
# 0 # | # 0 # | # 0 #
# 0 # | # 0 # | # 0 #
# 0 # | # 0 # | #   #
#   # | # 0 # | #   #
#   # | # 0 # | #   #
#   # | # 0 # | #   #
#   # | # 0 # | #   #
##### | ##### | #####

<强>予。简易方法算法

想法:想象一下斗圈。

步骤: 1.)取第一个桶,如果达到容量,则取出所有额外的石块并将其放入下一个桶中。然后去下一个桶。

2。)如果达到第二个铲斗容量,则将所有附加钻石放入下一个铲斗。如果没有达到容量。转到下一个桶

...

完成:不容易检查,但是如果你遍历所有桶并且没有达到容量的桶,那么你就完成了。

示例:

步骤1:A中有4颗石头。将4块石头移到B.现在A有0块石头,B有12块石头。

   4
A  -> B
4  0 12

步骤2:A为空。 B有12块石头。现在将7颗石头从B移到C.B现在有5块石头和10块石头。

   4    7
A  -> B -> C
4  0 12 5  10

步骤3:A为空。 B有5块石头和10块石头。现在从C到A移动5块石头.C现在有5块石头和5块石头,B还有5块石头。

   4     7     5
A  -> B  -> C  -> A
4  0  12 5  10 5  5

移动的石头= 15

交易= ->符号的3倍

希望您了解我的符号计算方法: - )

<强> II。智能算法

想法:你知道什么桶达到了容量以及什么桶有可用容量。

步骤:

1。)迭代所有桶并记住达到容量和额外石块数量的桶(列表1)。还要记住额外列表中剩余可用容量的桶(列表2)和可用空间量。

2。)迭代列表1并从列表2中取出第一项。然后将所有石头从容器A(从列表1)转移到B(从列表2,B可能达到容量!!!)。然后从A中删除Bucket 1,从B中删除Bucket。

3。)这样做直到一个列表没有任何项目

4.。)进入步骤1并按照步骤2-4进行操作。如果列表1没有任何项目,请完成此操作。

示例:

步骤1:List1 = {B = 3}且List2 = {A = 1,C = 2}。如果你看看下一个算法那么你就知道为什么我记得桶A中的其他石头的值3,以及桶A中的1个缺失的石头或桶B中的2个密苏石!

步骤2:从List1中获取B,从List2中获取A.现在移动3块石头如下。从List1中删除B,从List2中删除A.现在List1为空,所以从步骤1开始。

   3
 B -> A
 8 5  7

步骤1迭代2:List1 = {A = 2}且List2 = {C = 2}。见B不在任何列表中!!!

第2步迭代2:从List2获取A,从List2获取C.现在移动2块石头,如下所示。从List2中删除A,从List2中删除C.现在List1为空,所以从步骤1开始。

   3    2
 B -> A -> C
 8 5  7 5  5

步骤1迭代3:List1 = {}和List2 = {}。看到两个列表都是空的(但重要的只是list1),所以我们完成了!

Moved Stones = 5

交易= ->符号的2倍

<强> III。更智能的算法

想法:你知道什么桶达到了容量以及什么桶有可用容量。但现在我们记得额外或遗失的石头数量,但请看下面。

示例:

第1步:List1 = {B = 3},List2 = {A = 1,C = 2}

第2步:

   1
 B -> A
 8 5  5

   2
 B -> C
 8 5  5

成品。所有铲斗现在都有5块石头!

Moved Stones = 3

交易= ->符号的2倍

这是我的帖子的结尾

也许有更好的算法,但我不知道它们的名字,我不想写更多的解释。但我希望我能给你一些可能的实施方法。

也许其他人可以按名称命名一些算法!