AOJ0091 Blur
問題リンク Blur
- 解法
DFS+枝刈りで解きました。
f(i, j, k, drop): 既にk滴使っている状態でマス(i, j)に大きさdropの滴を落とす
という関数を作っておいて、左上から右下のマスへこの関数を再帰させます。
問題が与えている座標系は(x, y)座標ですが、自分は癖で行列(i, j)で座標を扱ってます。
このままだとTLEするっぽいので、枝刈りを入れます。
f()を左上から右下へ動かすので、(i, j)に大きさ3の滴を落としても届かない上部のマスは、これ以降絶対に滴を落とせません。なので、その部分に染料の量が合っていないマスが存在したら、目標の模様は作れないと決定するので枝を刈ります。
- ソース
import java.util.Scanner; //Blur public class AOJ0091 { int[][] dir = {{0,0},{-1,0}, {0,-1},{0,1},{1,0},{-1,-1},{-1,1},{1,-1},{1,1,},{-2,0},{0,-2},{0,2},{2,0}}; int[] num = {0, 5, 9, 13}; int[][] a, res; int L, V; boolean f(int i, int j, int k, int drop){ if(V==0)return true; if(k==L)return false; if(!check(i, j))return false; if(drop<1)return f(i, j+1, k, 3); if(i==9)return false; if(j==9)return f(i+1, 1, k, 3); if(a[i][j]==0)return f(i, j+1, k, 3); if(e(i, j, drop)){ for(int K=0;K<num[drop];K++)a[i+dir[K][0]][j+dir[K][1]]--; res[k][0] = j; res[k][1] = i; res[k][2] = drop; V-=num[drop]; if(f(i, j, k+1, drop))return true; V+=num[drop]; for(int K=0;K<num[drop];K++)a[i+dir[K][0]][j+dir[K][1]]++; } return f(i, j, k, drop-1); } boolean check(int i, int j){ i-=2; if(j<3){ i--; j=9; } else j-=3; while(0<=i && 0<=j){ if(a[i][j]>0)return false; if(j==0){ i--; j=9; } else j--; } return true; } boolean e(int i, int j, int drop){ for(int k=0;k<num[drop];k++){ int ni = i+dir[k][0], nj = j+dir[k][1]; if(ni<0||9<ni||nj<0||9<nj||a[ni][nj]==0)return false; } return true; } void run(){ Scanner sc = new Scanner(System.in); a = new int[10][10]; L = sc.nextInt(); V = 0; for(int i=0;i<10;i++)for(int j=0;j<10;j++){ a[i][j]=sc.nextInt(); V+=a[i][j]; } res = new int[L][3]; f(1, 1, 0, 3); for(int[]r:res)System.out.printf("%d %d %d\n", r[0], r[1], r[2]); } public static void main(String[] args) { new AOJ0091().run(); } }