AOJ1243 Weather Forecast
問題リンク Weather Forecast
- 概要
4*4の大きさの国があり、16個の町がある。そして2*2の大きさの雲がある。雲の下は必ず雨でそれ以外は晴れている。雲は国の国境をまたぐような位置にいることはできない。雲は最初に5,6,10,11の町の上部を覆う位置にいる。
雲は1日のはじめに上下左右に最大2マスまで動くか、その場にとどまることができる。斜めに動くことはできない。
N日間の各町の行事予定が与えられ、普通の日か祭りの日かを表す。
祭りの日に雨を降らせてはならない。また、7日間以上連続で雨が降らない町があってはならない。
これら2つの条件を満たすように雲を動かすことができるかを判定せよ。
N <= 365
- 解法
まず各町を0〜15で表すことにします。
雲がいることができるパターンは9通りで、その位置を0〜8で表します。cover[i][4]という配列に、雲が i にいるときに雨が降っている町を覚えさせておきます。また、move[i][5]に雲 i が次の日に動くことができる位置を入れておきます。
方針はメモ化探索です。
x日に雲がposにいて、そのとき、各町について残り何日で雨が降らなければならないか、という情報を持ってメモ化します。
3番目の情報については0〜6の範囲の数字が16個並ぶことになるのでlong型の整数として表すことができます。つまり、Set[x][pos]に既に探索した町の状態をメモしておくわけです。
後は、moveとcoverを使って探索をしていくだけです。
町の状態は7^16あるのでメモリが足りるか不安だったのですが、何とか大丈夫でした。
- ソース
import java.util.Arrays; import java.util.HashSet; import java.util.Scanner; import java.util.Set; //Weather Forecast public class AOJ1243 { int[][] cover = { {0,1,4,5}, {1,2,5,6}, {2,3,6,7}, {4,5,8,9}, {5,6,9,10}, {6,7,10,11}, {8,9,12,13}, {9,10,13,14}, {10,11,14,15} }; int move[][] = { {0,1,2,3,6}, {0,1,2,4,7}, {0,1,2,5,8}, {0,3,4,5,6}, {1,3,4,5,7}, {2,3,4,5,8}, {0,3,6,7,8}, {1,4,6,7,8}, {2,5,6,7,8} }; long trans(int[] a){ String s = ""; for(int x:a)s+=x; return Long.parseLong(s); } int n; boolean sun[][]; Set<Long>[][] set; //x日に雲がposに居てよいか boolean ok(int x, int pos){ for(int i=0;i<4;i++)if(sun[x][cover[pos][i]])return false; return true; } boolean get(int x, int pos, int[] a){ if(x==n)return true; if(set[x][pos].contains(trans(a)))return false; if(!ok(x, pos)){ set[x][pos].add(trans(a));return false; } for(int j=0;j<5;j++){ int[] t = new int[16]; for(int i=0;i<16;i++)t[i]=a[i]-1; int nx = move[pos][j]; for(int i=0;i<4;i++)t[cover[nx][i]] = 6; boolean f = true; for(int i=0;i<16;i++)if(t[i]<0)f = false; if(!f)continue; if(get(x+1, nx, t))return true; } set[x][pos].add(trans(a)); return false; } @SuppressWarnings("unchecked") void run(){ Scanner sc = new Scanner(System.in); for(;;){ n = sc.nextInt(); if(n==0)break; sun = new boolean[n][16]; for(int i=0;i<n;i++)for(int j=0;j<16;j++)sun[i][j] = sc.nextInt()==1; set = new HashSet[n][9]; for(int i=0;i<n;i++)for(int j=0;j<9;j++)set[i][j] = new HashSet<Long>(); int[] a = new int[16]; Arrays.fill(a, 5); if(!ok(0, 4)){ System.out.println(0);continue; } for(int j=0;j<4;j++)a[cover[4][j]] = 6; System.out.println(get(0, 4, a)?1:0); } } public static void main(String[] args) { new AOJ1243().run(); } }