AOJ2333 My friends are small
問題リンク My friends are small
- 解法
強引気味なメモ化探索で解きました。
まず思いついた方針は、重さwiを降順でソートし、
mem[i][j][k]: リュックの残り重量j、i番目以前の重さで使用しなかったものの最小値がkのとき、i番目以降を使ってリュックにつめる組み合わせ数
という表を埋めるようなメモ化探索です。ですがこれだと、N^2 * Wの大きさになってメモリが足りなくて困ります。でも、実際に使用する(i,j,k)の組み合わせはそれほど多くなく、使わない領域がかなりあるんじゃないかと予想したので、Map[i][j]というMapの2次元配列にし、kをMapのキーにするという方法でN^2*Wの表を用意することを回避しました。他の方の解よりは遅いですけど通りました。
- ソース
import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Scanner; //My friends are small public class AOJ2333 { int n, W, MOD = 1000000007; int[] w; Map<Integer, Integer>[][] mem; int get(int k, int rest, int min){ if(rest<0)return 0; if(k<0)return rest<min?1:0; if(mem[k][rest].containsKey(min))return mem[k][rest].get(min); int res = (get(k-1, rest, w[k])+get(k-1, rest-w[k], min))%MOD; mem[k][rest].put(min, res); return res; } @SuppressWarnings("unchecked") void run(){ Scanner sc = new Scanner(System.in); n = sc.nextInt(); W = sc.nextInt(); w = new int[n]; for(int i=0;i<n;i++)w[i]=sc.nextInt(); Arrays.sort(w); mem = new Map[n][W+1]; for(int i=0;i<n;i++)for(int j=0;j<=W;j++)mem[i][j]=new HashMap<Integer, Integer>(); System.out.println(get(n-1, W, 1<<29)); } public static void main(String[] args) { new AOJ2333().run(); } }