AOJ2157 Dial Lock

問題リンク Dial Lock

  • 概要

K桁のダイヤルロックがある。範囲[s, t](0 <= s <= t < K)を選んで、この範囲のダイヤルを同時に任意の位置まで回すことができる。初期配置Sから、ロックが外れる配置Tにするために、ダイヤルを回す回数を最小化せよ。
1 <= K <= 10

  • 解法

DPの方針で考えていましたが、DFSで解きました。
ダイヤルの左側の数字sから考えていき、S_sとT_sの数字が違えば、数字を合わせるように回します。このとき、回す範囲の右端t (s <= t < K)を全て試します。sについて考えたらs+1について再帰的に考えます。ざっと、O(K!)かかりますが、意外と間に合ってくれます。

  • ソース
import java.util.Scanner;

//Dial Lock
public class AOJ2157 {

	int n, res;
	int[] now, ans;
	
	void f(int k, int cnt){
		if(res<=cnt)return;
		if(k==n){
			res = cnt; return;
		}
		if(now[k]==ans[k])f(k+1, cnt);
		else{
			int dif = ans[k]-now[k];
			if(dif<0)dif+=10;
			for(int j=k;j<n;j++){
				now[j] = (now[j]+dif)%10;
				f(k+1, cnt+1);
			}
			for(int j=k;j<n;j++)now[j] = (now[j]+10-dif)%10;
		}
	}
	
	void run(){
		Scanner sc = new Scanner(System.in);
		for(;;){
			n = sc.nextInt();
			if(n==0)break;
			now = new int[n];
			ans = new int[n];
			char[] s = sc.next().toCharArray();
			for(int i=0;i<n;i++)now[i]=s[i]-'0';
			s = sc.next().toCharArray();
			for(int i=0;i<n;i++)ans[i]=s[i]-'0';
			res = n;
			f(0, 0);
			System.out.println(res);
		}
	}
	
	public static void main(String[] args) {
		new AOJ2157().run();
	}
}