3

OK、ここで私がしなければならないことです

MCI (Mammoth Cakes Incorporated) の従業員として、非常に大きな層状のバースデー ケーキを作成するのがあなたの仕事です。レイヤード バースデー ケーキは、小さな円形のケーキの層を取り、それらを積み重ねることによって作られます。

仕事を遂行するには、さまざまなサイズのレイヤーが目の前を通過する間、大きなベルトコンベアの前に立ちます。気に入ったものを見つけたら、コンベア ベルトから外してケーキに追加できます。

次のルールに従う限り、ケーキに好きなだけレイヤーを追加できます。

レイヤーがケーキに追加されると、移動できなくなります。(アイシングが台無しになります。)したがって、レイヤーはケーキの上部にのみ追加できます.

各レイヤーは一度だけあなたの前を通過します。あなたはそれを取るか、それを残すことができます。それを取る場合は、ケーキの上に追加する必要があります。放っておくと、ベルトコンベアを下っていき、二度と戻りません。

ケーキの各層は、少なくとも下の層と同じくらい小さくする必要があります。小さいレイヤーの上に大きいレイヤーを配置することはできません。

コンベアベルトを下って来る層の直径(インチ単位)が事前に通知されます。あなたの仕事は、これらのレイヤーを使用して、可能な限り高いケーキを作成することです。たとえば、次のリストがコンベア ベルトを下って来る層の直径を表しているとします: 8 16 12 6 6 10 5

ケーキの最初の層 (直径 8 インチ) を使用するとします。つまり、2 番目のレイヤーを使用することはできません (サイズ 8 インチ、および 16 インチ > 8 インチのレイヤーが既にあるため)。同様に、3 番目のレイヤーを取得することはできませんが、4 番目のレイヤーを取得することはできます (6 インチ < 8 インチであるため)。

それに続いて、5 番目のレイヤーを使用することもできます (ルールは、一番上のレイヤーを大きくすることはできず、同じサイズにすることができます)。この方法で 4 層の高さのケーキを作成できます: 8 6 6 5 ただし、最初の層を続けて 2 番目の層から始めると、高さ 5 のケーキを作成できます。 16 12 6 6 5

プログラムは、1 行に 1 つずつ、複数の入力セットを処理します。各行は整数 N で始まり、コンベア ベルトに到着する順序でケーキ層のサイズを表す N の正の整数が続きます。N は常に負でない整数、0 N 100,000 です。各レイヤーの直径は 1 ~ 100,000 です。N = 0 が入力の終わりを示す行

 Sample Input
7 8 16 12 6 6 10 5
10 45 25 40 38 20 10 32 25 18 30
10 10 9 8 7 6 5 4 3 2 1
0

Sample Output
5
6
10

質問: ケーキの一番高い層を見つけてください

これまでに書いたものは次のとおりです。

import java.io.*;
import java.util.*;

public class cake
{
    private static String line;
    private static ArrayList storage = new ArrayList();
    private static Integer highestStack = 0;

    public static void main(String [] args)throws IOException
    {
          FileReader fin = new FileReader("cake.in");
        BufferedReader infile = new BufferedReader(fin);

        FileWriter fout = new FileWriter("cake.out");
        BufferedWriter outfile = new BufferedWriter(fout);


        line = infile.readLine();
        do
        {

            String[] temp = line.split(" ");
            String number;


                for(int j = temp.length-1; j!=0;  j--)
                {

                   if(Integer.parseInt(temp[j]) <= Integer.parseInt(temp[j-1]))
                   {
                       highestStack++;
                   }

                }

               storage.add(highestStack);
            //  Collections.sort(storage);



            line = infile.readLine();
        }while(!line.equals("0"));


        infile.close();
        outfile.close();

    }

}
4

6 に答える 6

2

いくつかの回答についてコメントしたように、ポイントが完全に欠けていますが、これは動的プログラミングの問題です。

制約を追加したので、O(n^2)で実行される動的計画法ソリューションが進むべき道であることは明らかであり、N が 100 000 を超えないという事実により、DP (および非 DP アルゴリズムを使用して解決するのはおそらく非常に困難です)。

あらゆる瞬間に、「「x」までできる最善のことは何か」と自問する必要があります。

最初の例では、次のようになります。

 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 (Best we can do using pieces: 5 )
 0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2 2 (Best we can do using pieces: 5 10 )
 0 0 0 0 0 1 2 2 2 2 2 2 2 2 2 2 2 (Best we can do using pieces: 5 10 6 )
 0 0 0 0 0 1 3 3 3 3 3 3 3 3 3 3 3 (Best we can do using pieces: 5 10 6 6 )
 0 0 0 0 0 1 3 3 3 3 3 3 4 4 4 4 4 (Best we can do using pieces: 5 10 6 6 12 )
 0 0 0 0 0 1 3 3 3 3 3 3 4 4 4 4 5 (Best we can do using pieces: 5 10 6 6 12 16 )
 0 0 0 0 0 1 3 3 4 4 4 4 4 4 4 4[5] (Best we can do using pieces: 5 10 6 6 12 16 8 )

 Tallest cake as a height of: 5

上の行を読む方法は簡単です。たとえば、最初の行を見てみましょう。

0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1

これは、基数が 5 から 16 までの最も高いケーキは、1 つの要素 (最初のピースである「5」) でできていることを意味します。

次にピース「10」を取得し、次の行を取得します。

0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2 2

これは、5 から 9 までで作ることができる最も高いケーキには 1 つの要素 (「5」) があり、10 から 16 まででは 2 つの部分 (5 と 10) を詰めることができることを意味します。

必要に応じて、最大 100 000 の要素を使用して、このように繰り返します。

私のコンピューターでは、動的計画法を使用して完全な 100 000 の解を解くのに 20 秒もかかりません。

問題を解決し、上記を出力するコードを次に示します。何が起こっているかを確認できるように、意図的に出力ステートメントを追加しました (実際には、アルゴリズムで何が起こっているかを取得するためだけに、比較的小さな数値でのみ見栄えがします)。

public static void main( String[] args ) {
    doIt( new int[] {8,16,12,6,6,10,5} );
    doIt( new int[] {0, 45, 25, 40, 38, 20, 10, 32, 25, 18, 30} ); 
    doIt( new int[] {10, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1} );
}

public static void doIt( int[] r ) {
    final int[] a= new int[r.length];
    int max = Integer.MIN_VALUE;
    for (int i = 0; i < a.length; i++) {
        max = Math.max( max, a[i] );
        a[(a.length-1)-i] = r[i];
    }
    final int[] s = new int[max+1];
    for (int i = 0; i < a.length; i++) {
        final int size = a[i];
        s[size]++;
        for (int j = size+1; j < s.length; j++) {
            s[j] = Math.max( s[j-1], s[j] );
        }
        for (int j = 0; j < s.length; j++) {
            System.out.print( " " + ((s[j]) > 9 ? "" : " ") + s[j] );
        }
        System.out.print( " (Best we can do using pieces: " );
        for (int k = 0; k <= i; k++) {
            System.out.print( a[k] + " " );
        }
        System.out.println( ")" );
    }
    System.out.println( "Tallest cake as a height of: " + s[s.length-1] );
}
于 2010-12-12T21:55:12.413 に答える
1

あなたが何を求めているのか正確にはわかりません..それで、いくつかの一般的なヒントを提供します。

ArrayList ではなく、Stack データ構造を調べます。 レイヤーをスタックにプッシュし、 peekを使用して、コンベア内の現在のアイテムに対するケーキスタックの最上層の直径を確認します。

目標が可能な限り高いケーキを見つけることである場合、素朴なアプローチは、コンベアの最初のレイヤーから始めて最後まで継続し、最終的な高さ ( stack.size() ) を記録することによって、単純に上記のアルゴリズムを適用することです。次に、コンベヤーの 2 番目のアイテムをベースとして繰り返し、次に 3 番目のアイテムをベースとして繰り返し、各ループの最後に記録された最大値に対して結果の高さを比較します。

于 2010-12-12T19:42:10.080 に答える
1

プロセスを見てみましょう。組み立てラインでレイヤーに遭遇するたびに、このレイヤーを使用するかどうかを決定します。全体として最良の結果は、次の 2 つの結果のうち優れているものです。

  • このレイヤーを使用し、このレイヤーより大きくない残りのレイヤーを使用して、その上に最も高いケーキを構築します。

  • このレイヤーは使用せず、残りのレイヤーのいずれかを使用して最も高いケーキを作成します。

これを再帰で簡単にモデル化できます - 疑似コード:

tallest(remaining_layers, base_size) = # set base_size = infinity the first time
    max(
        first_layer + tallest(other_layers, size(first_layer)),
        tallest(other_layers, base_size)
    )
    where first_layer = first(remaining_layers),
          other_layers = rest(remaining_layers)

ただし、動的計画法を使用することになっているため、それだけではうまくいきません。

アイデアは、両方の時間で再帰的に呼び出しているということですtallestother_layers一度呼び出して、必要なすべての情報を入手できたらいいと思いませんか?

どのような情報が必要ですか? 基本サイズの残りのレイヤーを使用して最も高いケーキを作成した場合、設定は完了です。現在のレイヤーに収まる最も高いケーキを選択し、それが最も高いケーキ全体に対して改善されるかどうかを確認します。しかし、ここに秘訣があります。改善されなくても、情報は得られる可能性があります。アイデアは、各サイズの最も「効率的な」(最小のベース) ケーキのリストを作成することです。

したがって、私たちのプロセスは次のようになります。

Set up a list of cakes, with one cake in it that has zero layers.
# There will be, at all times, one cake in the list of any given height.
# Starting at zero instead of one makes the iteration neater.
For each layer on the conveyor belt, working **backwards** from the last:
    Find the tallest cake in the list that fits on this layer.
    Construct the cake 'c' consisting of that cake on top of this layer.
    If there is already a cake in the list of the same height as 'c':
        If the other cake has a smaller base, throw 'c' away. # It didn't help.
        Otherwise, remove the other cake from the list. # 'c' is better.
    If we still have 'c', add it to the list.
The tallest possible cake for the input is now the tallest one in the list.
于 2010-12-12T21:44:16.467 に答える
1

この入力シーケンスはトリッキーです:

10 45 25 40 38 20 10 32 25 18 30

導入レイヤーのみをスキップする単純なアプローチでは、次の [ケーキ] が見つかります。

[10]  45   25   40   38   20   10   32   25   18   30 
 10  [45   25]  40   38   20   10   32   25   18   30
 10   45  [25]  40   38   20   10   32   25   18   30
 10   45   25  [40   38   20   10]  32   25   18   30   <-- naive tallest, 4
 10   45   25   40  [38   20   10]  32   25   18   30
 10   45   25   40   38  [20   10]  32   25   18   30
 10   45   25   40   38   20  [10]  32   25   18   30
 10   45   25   40   38   20   10  [32   25   18]  30
 10   45   25   40   38   20   10   32  [25   18]  30
 10   45   25   40   38   20   10   32   25  [18]  30
 10   45   25   40   38   20   10   32   25   18  [30]

ただし、ゲームのルールでは、先頭のレイヤーだけでなく、任意のレイヤーをスキップできます。したがって、この場合の正しい最も高いケーキは次のようになります。

 10  [45]  25  [40] [38]  20   10  [32] [25] [18]  30 

または、選択したレイヤーのみを書き出す:

 45   40   38   32   25   18  
于 2010-12-12T21:19:57.043 に答える
1

あなたが解決しようとしている問題は、動的プログラミングの問題です (単純なものではありますが)。

アルゴリズム

public static int findMaxHeight(int[] layers) {
  int[] max = new int[layers.length];
  
  for(int i=layers.length - 1; i >= 0; i--) {
    int localMax = 0;
    for(int j=0; j < layers.length; j++) {
      if(layers[j] < layers[i]) {
        if(max[j] > localMax) {
          localMax = max[j];
        }
      }
    }

    max[i] = localMax + 1;    
  }
  
  int height = 0;

  for(int i=0; i < max.length; i++) {
    if(max[i] > height) {
      height = max[i];
    }
  }

  return height;
}

ステップバイステップ

これがどのように機能するかのステップとして、次のことを考慮してください。

8 16 12 6 6 10 5

順番が逆なので、

5 10 6 6 12 16 8

5 から始めて、[] から 5 未満の値があります。

5 10 6 6 12 16 8
1

[5] から、最大 [5] = 1 なので 1+1

5 10 6 6 12 16 8
1  2

等々...

5 10 6 6 12 16 8
1  2 2 3  4  5 4

次に、リスト [1, 2, 2, 3, 4, 5, 4] の最大値である 5 を見つけます。

そして、上で説明したように、これは彼が問題の説明でステップスルーした提供された例に対する正しい答えです。


使い方

このアルゴリズムは、各レイヤーの最大値を保存することによって機能します。質問は、任意の層について、その直径以下のケーキのみを積み重ねることができることを説明しています. したがって、特定のレイヤーの最大値は常に、ベルト上でそれに続く同じサイズまたはそれ以下のサイズのレイヤーの最大値に 1 を加えたものになります (レイヤー自体を数えます)。その上にスタックできるレイヤーがない場合、このレイヤーの最大値は 1 であることがわかります。

于 2010-12-12T21:43:24.580 に答える
0

実際には非常に単純で、次のようになります。

int[] layers = new int[] {x1,x2,x3...xn};    
int[] count = new int[layers.length];

for(int i = 1; i < layers.length; i++)
{             
       for(int j = i+1 ; j < layers.length; j++)
       {
         if ( layers[j] >= layers[i]) count[i]++; 
       }     
 }

 answer = Collections.max(Arrays.asList(count));
于 2010-12-13T01:50:04.403 に答える