2015-06-16 58 views
2

嗨,我是一個搜索算法來解決以下問題:搜索算法 - 桶和石頭

有n個水桶和y的石頭,可以扔進桶。每個學生在隨機桶中投擲石塊x次後,桶中的石塊數量不同。現在這位教授帶着100個Post-Its,隨機把這些帖子放在桶上。他說:「每個Post-Id指示所有桶中的石頭數量的百分之一,所以如果桶A有10個Post-It,那麼如果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

是否保證您可以生產每個百分比?如果* y *是* 17 *(素數)會怎麼樣? –

+0

是的,爲什麼不。你有3個桶(= x)和17個石塊(= y)。也許桶A獲得3石,B 7石和C也7石。 – aexerus

+1

您能否澄清一下:「請更改桶中的石塊數量,因此每個桶中都有**最多的石塊**,**最小變化率的團隊**」?特別是粗體部分。另外,石頭如何移動?從任何桶到任何桶的組?無論有多少石頭移動多遠,這是否被認爲是一舉一動? –

回答

1

我不知道你的意思,但我會試着通過一個理解的例子來理解你的要求。

推介石頭= 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石頭

初始石頭(s ymbol 0)鬥:

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

一,最簡單的辦法算法

理念:想象一下,一個吊桶環。

步驟: 1.)第一桶,如果capcacity達到了所有額外的石頭,並把它放到下一個桶。然後去下一個桶。如果達到第二桶容量,則將所有附加石塊放到下一個桶中。如果容量未達到。轉到下一個桶

....

成品:不容易檢查,但如果你遍歷所有的桶和桶沒有達到能力,那麼你就完成。

實施例:

步驟1:4-結石A.移動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塊石頭,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和桶2從B.

3.刪除桶1)這樣做,直到一個名單沒有任何項目

4)得到第1步,然後按照步驟2-4。如果清單1沒有剩下任何物品,請完成此操作。

實施例:

步驟1:列表1 = {B = 3}和列表2 = {A = 1,C = 2}。如果你看看下一個算法,那麼你知道爲什麼我記住A桶中額外石塊的價值3,以及桶B中有1塊缺失石塊或桶B中有2塊石洞石塊!

第2步:從List1中取B,從List2取A。現在像下面移動3塊石頭。從List1中刪除B,從List2中刪除A.現在List1中是空的,所以與第1步。

3 
B -> A 
8 5 7 

步驟1迭代2開始:列表1 = {A = 2}和列表2 = {C = 2}。看到B不在任何列表中!

第2步迭代2:從List1中取A,從List2取C。現在移動2個像下面的石頭。從List1中刪除A,從List2中刪除C.現在List1爲空,所以從步驟1開始。

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

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

移至石= 5個

事務= 2倍的符號->


III。一個更智能的算法

想法:你知道什麼桶達到了容量和哪個桶剩餘空閒容量。但現在我們記住額外的或失蹤的石頭的數量,但看下面。

實施例:

步驟1:列表1 = {B = 3}和列表2 = {A = 1,C = 2}

步驟2:

1 
B -> A 
8 5 5 

    2 
B -> C 
8 5 5 

成品。所有桶現在有5塊石頭!

遷石= 3個

事務= 2倍的->標誌


這是我的帖子的末尾


也許還有尤爲明顯算法,但我確實不知道他們的名字,我不想寫更多的解釋。但是我希望我能給你一些關於可能的實現的想法。

也許一些其他人可以命名一些算法的名稱!