嗨,我正在搜索一个算法来解决以下问题:
有N个桶和Y个石头,可以扔进桶里。每个学生在随机的桶里扔石头x次后,桶里的石头数就不同了现在教授取了100个贴子,随机地把这些贴子贴在桶上。他说:“每个post id都表示所有bucket中石头数量的百分之一,因此如果bucket a有10个post its,那么如果y=100(总石头数量),它最后可以有10个stone。请更换桶中的石头量,因此每个桶都有最大的石头,最小的转移量(见下面的转移动作)赢了啤酒!
这应该是一个常见的分配问题,但我不知道如何解决它。我必须找到一个具有最小更改操作的algo,所以我会进行一些汇总统计,找出一些运行/试用/时间内的最佳algo。
有人能帮我指一下最好的算法吗?
有一些限制:所以不可能把所有的石头放在一个桶里,然后放回正确的数量!最小的意思是,桶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类(best algo没有很多fillAction):
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;
    }
}

最佳答案

我不太明白你的意思,但我会试着用一个我理解的例子来理解你的要求。
可用石材=x15
桶=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石
桶中的初始石头(符号0):

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

一、简易算法
想法:想象一个桶环。
步骤:
1.)取第一个桶,如果达到容量,则取所有额外的石头并将其放在下一个桶中。去下一个桶。
2.)如果达到第二个桶容量,则将所有额外的石头放在下一个桶中。如果没有达到容量。转到下一个桶
....
完成:不容易检查,但是如果您遍历所有bucket,并且没有bucket达到容量,那么您就完成了。
例子:
步骤1:A中有4块石头。移动4块石头到B。现在A有0块石头,B有12块石头。
   4
A  -> B
4  0 12

步骤2:A为空。B有12块石头现在把7块石头从B移到C。B现在有5块石头和C 10块石头。
   4    7
A  -> B -> C
4  0 12 5  10

步骤3:A为空。B有5块石头,C有10块石头。现在把5块石头从C移到A。C现在有5块石头,A有5块石头,B还有5块石头。
   4     7     5
A  -> B  -> C  -> A
4  0  12 5  10 5  5

移动的石头=15
交易=3倍的->签名
希望你能理解我的符号计算方法:-)
二一种智能算法
想法:你知道什么桶达到了容量,什么桶还有剩余的空闲容量。
步骤:
1.)遍历所有存储桶,记住已达到容量的存储桶和添加的石头数量(列表1)。还要记住额外列表(列表2)中剩余可用容量的存储桶和可用空间量。
2.)遍历列表1并从列表2中获取第一项。然后将超过容量的所有石头从桶A(从列表1)转移到桶B(从列表2,B可能达到容量!!!)。然后从a中删除bucket 1,从b中删除bucket 2。
3.)在一个列表中没有任何项目之前执行此操作
4.)进入步骤1,然后执行步骤2-4如果列表1没有任何项目,请完成此操作。
例子:
第一步:List1={B=3}和List2={A=1,C=2}如果你看一下下一个算法,你就会知道为什么我会记住桶a中的额外石头值3,桶a中的丢失石头值1,桶B中的错长石头值2!
步骤2:从列表1中获取B,从列表2中获取A。现在像下面那样移动3块石头。从列表1中删除B,从列表2中删除A现在list1是空的,所以从步骤1开始。
   3
 B -> A
 8 5  7

步骤1迭代2:List1={A=2}和List2={C=2}看B不在任何名单上!!!
第2步迭代2:从List1获取A,从List2获取C现在像下面那样移动两块石头从列表1中删除a,从列表2中删除c。现在list1是空的,所以从步骤1开始。
   3    2
 B -> A -> C
 8 5  7 5  5

步骤1迭代3:list1={}和list2={}。看两个列表都是空的(但重要的是只有列表1),所以我们完成了!
移动的石头=5
交易=2倍的->签名
三、更智能的算法
想法:你知道什么桶达到了容量,什么桶还有剩余的空闲容量。但现在我们想起了额外的或丢失的石头的数量,但看看下面。
例子:
第一步:List1={B=3}和List2={A=1,C=2}
步骤2:
   1
 B -> A
 8 5  5

   2
 B -> C
 8 5  5

完成了所有水桶现在都有5块石头!
移动的石头=3
交易=2倍的->签名
我的职位到此结束
也许有更好的算法,但我不知道他们的名字,我不想写更多的解释。但我希望我已经给你一些可能的实现的想法。
也许其他人可以用名字命名一些算法!

10-06 09:16