Pku JudgeOnline
今日解いた問題はhttp://acm.pku.edu.cn/JudgeOnline/problem?id=2411
1×2のタイルでh×w(h,w<=11)の面を敷き詰める方法は何通りあるか?
再帰的に全探索する.ただし,h段目を埋めるときにはh-1段目のタイルの形状だけに注目すればよいので,メモ化が効いてmax(h,w)*(2^min(h,w))ぐらいの記憶領域を用いれば,TLEを出さずにすむ.
この方法は昨年のICPCの学科の練習会でコーチの人に教えられて,感心したのだが今日解いてないことに気付いて解いた.
ソースは以下の通り.
いちいちビットを配列に直しているのが非常にいけてない.
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(true){ int h = sc.nextInt(); int w = sc.nextInt(); if(h==0 && w==0)break; long memo[][] = new long[h][1<<w]; for(int i=0;i<memo.length;i++){ Arrays.fill(memo[i], -1); } System.out.println(f(w,memo.length-1,memo[0].length-1,memo)); } } static void toArr(int val,int index,boolean arr[]){ if(index==arr.length)return; arr[index] = (val%2==1); toArr(val/2,index+1,arr); } static long f(int width,int h,int pattern,long memo[][]){ if(h<0){ if(pattern==memo[0].length-1)return 1; return 0; } if(memo[h][pattern]>=0)return memo[h][pattern]; long res = 0; boolean arr[] = new boolean[width]; for(int p=0;p<memo[0].length;p++){ // p : w1*h2の置き方 //patternと重なる必要がある. if((pattern|p)!=pattern)continue; //p2 : w2*h1の置き方 int p2 = pattern ^ p; toArr(p2,0,arr); boolean f = true; for(int i = 0;i<arr.length;i++){ if(arr[i]){ if(i+1==arr.length || (!arr[i+1])){ f = false; break; }else{ i++; } } } if(!f)continue; long v=f(width,h-1,(memo[0].length-1)^p,memo); res += v; } memo[h][pattern] = res; return res; } }
追記:
配列に変換部分を消す,あと無駄に行数を減らしてみた.
import java.util.*; public class Main { static long memo[][]; public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(true){ int h = sc.nextInt(); int w = sc.nextInt(); if(h==0 && w==0)break; memo = new long[h][1<<w]; for(int i=0;i<memo.length;i++)Arrays.fill(memo[i], -1); System.out.println(f(h-1,(1<<w)-1)); } } static long f(int h,int pattern){ if(h<0)return pattern==memo[0].length-1?1:0; if(memo[h][pattern]>=0)return memo[h][pattern]; memo[h][pattern] = 0; l:for(int p=0;p<memo[0].length;p++){ if((pattern|p)!=pattern)continue; int p2 = pattern^p; for(int i=1;i<=memo[0].length;i*=2){ if((i&p2)!=0){ i *=2; if((i&p2)==0)continue l; } } memo[h][pattern] +=f(h-1,(memo[0].length-1)^p); } return memo[h][pattern]; } }